You have a mismatch on the calling convention. The typedef in your C++ code declares a function pointer with the default calling convention, which is __cdecl. But the default for a delegate in managed code is __stdcall.
You will need an attribute to tell the pinvoke marshaller otherwise. Make that look like this:
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void TestDelegate(string info);
Drop the [MarshalAs] in the function declaration. Fixing the typedef in your C++ code might be preferable, if you can, clearly making everything consistent is the preferred solution:
typedef void (__stdcall * TESTCALLBACK_FUNCTION )(char* msg);
Unrelated, this a bug you'll need to fix:
unmanaged.put_TestCallBack(new TestDelegate(this.Test));
The delegate object you create is not visible to the garbage collector. If will be collected on the next GC, your code will crash when the native code makes the callback. You have to store the delegate object somewhere so the GC always sees a reference. Either as a field in the class, with the additional requirement that the class object needs to stay alive long enough, or in a static variable.
Note how all of these problems disappear when you declare a callback interface instead of a delegate. The COM way.