есть такая куча документов как msdn
тебе должно помочь
каркас dll (если пишешь в visual c++) создается так: file->new project
дальше в визарде вибираешь dll и в additional options exports symbols
это в visual studio .net 2003 в (vc 6 вроде такое же)
чтобы нормально экспортировать функции из длл (и еще для разных компиляторов) лучше создавать .def файл (в msdn про это пишут)
для классов сказать не могу (т.к. у разных компиляторов разный способы названия методов)
в этом случае должны помочь абстрактные классы или интерфейсы (как в COM, например)
чтобы возвращать строку надо ее создать либо в статической области памяти (но про потоки можешь забыть, если аккуратно не писать программу), либо в динамической памяти (но надо решить вопрос кто будет удалять эту самую строку)
про стек тоже можешь забыть если не хотишь хлебнуть лиха
еще такой момент: если ты резервируешь память в длл, а освобождаешь в программе которая использует эту длл (или наооборот, по этому надо посмотреть в сторону интерфейса IMalloc или функций CoTaskMemAlloc и иже с ними) тоже можешь хлебнуть лиха (и очень долго искать причину ошибки)
p.s. C++ позволяет делать с памятью (и не только с ней) все что хотишь, но и расплачиваться за это надо тем, что C++ ничего не скажет про то что у тебя есть ошибка (именно семантическая)