One thing I might add is that using std::wstring within your C++ dll would be perfectly fine, and likely you are comfortable with that. Where the problem comes in is the interface between the C++ dll and .NET. Of course that interface is through exported functions with their parameter lists. Incoming strings of whatever form could be converted to std::wstring within your dll for you to make use of the std::wstring members. Same thing with outgoing strings. You could convert them from std::wstring to BSTRs quite easily.
The more I think about it, I'm thinking the .NET string type must internally be a BSTR. The reason I say that is because a number of years ago I wrote an ActiveX Grid Control using all low level COM code, i.e., no ATL wrappers or anything like that, and I tested it in VB.NET, and it works fine there. The BSTR parameters I used just showed up as regular .NET strings, and the intellisense IDE recognized them as such.
If you have a std::wstring object such as this...
Code:
std::wstring s1(L"Hello, World!");
...to convert that to a BSTR its just something ike this...
Code:
BSTR strHello=SysAllocString(s1.c_str());
The main issue in using these creatures from C++ is you need to be very careful about memory leaks, as most allocated BSTRs need to be released. That article by Allen McKinney above goes into that.