Я использую следующую функцию, чтобы попытаться получить путь к папке с документами, а затем преобразовать этот путь в std :: string:
std::string getpath() {
TCHAR documents[MAX_PATH];
HRESULT result = SHGetFolderPath(NULL, CSIDL_PERSONAL, NULL, SHGFP_TYPE_CURRENT, documents);
std::stringstream pff;
pff << result;
return pff.str();
}
Когда это выполняется, я получаю «недопустимую ошибку имени файла» при попытке добавить «\ filename» в строку.
Пожалуйста помоги!
Редактировать: вот как я добавляю к пути:
std::string folder = getpath() + "\\Folder";
Я предполагал, что символы двойного побега будут по-прежнему применяться.
Вы не печатаете documents
, но result
,
Попробуйте что-то вроде этого:
std::string getpath() {
TCHAR documents[MAX_PATH];
HRESULT result = SHGetFolderPath(NULL, CSIDL_PERSONAL, NULL, SHGFP_TYPE_CURRENT, documents);
if (result == S_OK) // SUCCEEDED(result) can be problematic
// since S_FALSE is a possible return value
{
std::stringstream pff;
pff << documents;
return pff.str();
}
// handle error somehow
return "";
}
И это версия для Unicode:
std::wstring getpath() {
TCHAR documents[MAX_PATH];
HRESULT result = SHGetFolderPath(NULL, CSIDL_PERSONAL, NULL, SHGFP_TYPE_CURRENT, documents);
if (result == S_OK) // SUCCEEDED(result) can be problematic
// since S_FALSE is a possible return value
{
std::wstringstream pff;
pff << documents;
return pff.str();
}
// handle error somehow
return L"";
}
Ваш код терпит неудачу, потому что вы действительно строите строку из возвращаемое значение (т.е. код ошибки) из SHGetFolderPath. Вместо этого вы должны использовать возвращаемый путь.
поскольку SHGetFolderPath
устарела, вы должны использовать SHGetKnownFolderPath вместо. Помимо прочего, вы не будете случайно создавать имя пути в кодировке MBCS. И нет произвольного MAX_PATH
(260) ограничение символов.
Следующий код извлекает путь к документу текущего пользователя1:
#include <string>
#include <ShlObj.h>
#include <comdef.h>
std::wstring GetDocumentPath() {
wchar_t* pOut = nullptr;
// Retrieve document path (CheckError throws a _com_error exception on failure)
_com_util::CheckError( ::SHGetKnownFolderPath( FOLDERID_Documents, KF_FLAG_DEFAULT,
nullptr, &pOut ) );
// Attach returned buffer to a smart pointer with custom deleter. This
// is necessary, because the std::wstring c'tor throws on failure.
// Without this smart pointer, any exception would leak memory.
auto deleter = []( void* p ) { ::CoTaskMemFree( p ); };
std::unique_ptr<wchar_t, decltype( deleter )> buffer{ pOut, deleter };
return std::wstring{ buffer.get() };
// Invisible: Run deleter for buffer, cleaning up allocated resources.
}
Замечания: _com_util::CheckError
официально не задокументировано, поэтому оно может стать недоступным в будущей версии компилятора. Пользовательская реализация со схожей функциональностью может выглядеть так:
inline void CheckError( HRESULT hr ) {
if ( FAILED( hr ) ) {
_com_raise_error( hr );
}
}
_com_raise_error задокументировано, чтобы бросить _com_error исключение. НЕ УДАЛОСЬ макрос также задокументирован.
1 Известные пути к папкам настраиваются (см. Обзор перенаправления папок). Вы не можете просто попытаться построить их самостоятельно. Вы должны спросить у Shell эту информацию.
Я закончил тем, что бросил SHGetFolderPath и пошел с более прямыми _dupenv_s:
std::string getpath() {
char* buf = 0;
size_t sz = 0;
if (_dupenv_s(&buf, &sz, "USERPROFILE") == 0) {
std::string path(buf);
path += "\\Documents\\Folder";
return path;
}
return NULL;
}