使用Windows API获取用户的桌面文件夹?

我正在尝试通过使用SHGetSpecialFolderPath在C ++应用程序(通过DLL)中获取用户的Desktop文件夹:

 #define _WIN32_WINNT 0x0500 #define _WIN32_IE 0x0500 #define CSIDL_MYMUSIC 0x000D #define CSIDL_MYVIDEO 0x000E #include "dll.h" #include <windows.h> #include <shlobj.h> #include <stdio.h> TCHAR path[MAX_PATH]; export LPSTR desktop_directory() { if (SHGetSpecialFolderPath(HWND_DESKTOP, path, CSIDL_DESKTOP, FALSE)) { return path; } } 

首先,我想返回一个其他情况。 我返回“错误”,但编译器警告我试图将CHAR转换为LPSTR 。 如果有的话,它看起来如果由于某种原因无法获取目录,DLL可能会崩溃。

同样从MSDN文档,它说:“[SHGetSpecialFolderPath不支持,而是使用ShGetFolderPath。]”,然后我导航到该页面,它说:“ShGetFolderPath:弃用。获取由CSIDL值标识的文件夹的path。 我应该用什么来代替?

所以:

  1. 我想添加一个别的情况下,我返回一个string说“错误”
  2. 我想知道如果我正在使用正确的非弃用的API函数,可以用于Windows XP的现代Windows操作系统。

编辑

这是根据要求更新的代码,

 #ifndef UNICODE #define UNICODE #endif #ifndef _UNICODE #define _UNICODE #endif #define _WIN32_WINNT 0x0500 #define _WIN32_IE 0x0500 #define CSIDL_MYMUSIC 0x000D #define CSIDL_MYVIDEO 0x000E #include "dll.h" #include <windows.h> #include <shlobj.h> #include <stdio.h> export LPCWSTR desktop_directory() { static wchar_t path[MAX_PATH+1]; if (SHGetFolderPath(NULL, CSIDL_DESKTOP, NULL, 0, path)) { MessageBox(NULL, path, L"TEST", MB_OK); //test return path; } else { return L"ERROR"; } } 

用MinGW编译使用: g++ "src\dll\main.cpp" -D UNICODE -D _UNICODE -O3 -DNDEBUG -s -shared -o "output\main.dll"

我需要使用WideCharToMultiByte(CP_UTF8, ...)作为UTF-8从DLL传递string,但我不知道如何做到这一点。

SHGetFolderPath()返回一个HRESULT ,其中0是S_OK ,但是你的代码期望它返回一个像SHGetSpecialFolderPath()那样的BOOL ,其中0是FALSE 所以你需要在你的代码中修正这个错误,因为它现在正在把一个成功看成是一个失败。

这就是说,你正在从你的函数返回一个LPSTR 这是一个char* 但是你正在使用TCHAR作为你的缓冲区。 根据是否定义了UNICODE TCHAR映射到charwchar_t 所以你需要决定是否要无条件地返回一个char* ,或者如果你想返回一个TCHAR* ,或者两者兼有。 它有很大的不同,例如:

 #define _WIN32_WINNT 0x0500 #define _WIN32_IE 0x0500 #define CSIDL_MYMUSIC 0x000D #define CSIDL_MYVIDEO 0x000E #include "dll.h" #include <windows.h> #include <shlobj.h> #include <stdio.h> export LPSTR desktop_directory() { static char path[MAX_PATH+1]; if (SHGetSpecialFolderPathA(HWND_DESKTOP, path, CSIDL_DESKTOP, FALSE)) return path; else return "ERROR"; } 

与:

 #define _WIN32_WINNT 0x0500 #define _WIN32_IE 0x0500 #define CSIDL_MYMUSIC 0x000D #define CSIDL_MYVIDEO 0x000E #include "dll.h" #include <windows.h> #include <shlobj.h> #include <stdio.h> export LPTSTR desktop_directory() { static TCHAR path[MAX_PATH+1]; if (SHGetSpecialFolderPath(HWND_DESKTOP, path, CSIDL_DESKTOP, FALSE)) return path; else return TEXT("ERROR"); } 

与:

 #define _WIN32_WINNT 0x0500 #define _WIN32_IE 0x0500 #define CSIDL_MYMUSIC 0x000D #define CSIDL_MYVIDEO 0x000E #include "dll.h" #include <windows.h> #include <shlobj.h> #include <stdio.h> export LPSTR desktop_directory_ansi() { static char path[MAX_PATH+1]; if (SHGetSpecialFolderPathA(HWND_DESKTOP, path, CSIDL_DESKTOP, FALSE)) return path; else return "ERROR"; } export LPWSTR desktop_directory_unicode() { static wchar_t path[MAX_PATH+1]; if (SHGetSpecialFolderPathW(HWND_DESKTOP, path, CSIDL_DESKTOP, FALSE)) return path; else return L"ERROR"; } 

更新:大多数Win32 API函数不支持UTF-8,所以如果你想让函数返回一个UTF-8字符串,你将不得不调用函数的Unicode风格,然后使用WideCharToMultiByte()将输出转换为UTF-8。 但是你有一个问题 – 谁分配和释放UTF-8缓冲区? 有几种不同的方式来处理:

  1. 使用线程安全的静态缓冲区(但要注意这个问题 )。 如果不需要担心访问该函数的多个线程,则放弃__declspec(thread)说明符:

     #define _WIN32_WINNT 0x0500 #define _WIN32_IE 0x0500 #define CSIDL_MYMUSIC 0x000D #define CSIDL_MYVIDEO 0x000E #include "dll.h" #include <windows.h> #include <shlobj.h> #include <stdio.h> __declspec(thread) char desktop_dir_buffer[((MAX_PATH*4)+1]; export LPCSTR desktop_directory() { wchar_t path[MAX_PATH+1] = {0}; if (SHGetFolderPathW(NULL, CSIDL_DESKTOPDIRECTORY, NULL, 0, path) != S_OK) { MessageBoxW(NULL, L"ERROR in SHGetFolderPathW", L"TEST", MB_OK); return NULL; } MessageBoxW(NULL, path, L"TEST", MB_OK); int buflen = WideCharToMultiByte(CP_UTF8, 0, path, lstrlenW(path), desktop_dir_buffer, MAX_PATH*4, NULL, NULL); if (buflen <= 0) { MessageBoxW(NULL, L"ERROR in WideCharToMultiByte", L"TEST", MB_OK); return NULL; } desktop_dir_buffer[buflen] = 0; return desktop_dir_buffer; } 
  2. 让DLL使用自己的内存管理器动态分配缓冲区,并将其返回给调用者,然后要求调用者在使用DLL时将缓冲区传递回DLL,以便可以使用DLL的内存管理器来释放缓冲区:

     #define _WIN32_WINNT 0x0500 #define _WIN32_IE 0x0500 #define CSIDL_MYMUSIC 0x000D #define CSIDL_MYVIDEO 0x000E #include "dll.h" #include <windows.h> #include <shlobj.h> #include <stdio.h> export LPCSTR desktop_directory() { wchar_t path[MAX_PATH+1] = {0}; if (SHGetFolderPathW(NULL, CSIDL_DESKTOP, NULL, 0, path) != S_OK) { MessageBoxW(NULL, L"ERROR in SHGetFolderPathW", L"TEST", MB_OK); return NULL; } MessageBoxW(NULL, path, L"TEST", MB_OK); int pathlen = lstrlenW(path); int buflen = WideCharToMultiByte(CP_UTF8, 0, path, pathlen, NULL, 0, NULL, NULL); if (buflen <= 0) { MessageBoxW(NULL, L"ERROR in WideCharToMultiByte", L"TEST", MB_OK); return NULL; } char *buffer = new char[buflen+1]; buflen = WideCharToMultiByte(CP_UTF8, 0, path, pathlen, buffer, buflen, NULL, NULL); if (buflen <= 0) { delete[] buffer; MessageBoxW(NULL, L"ERROR in WideCharToMultiByte", L"TEST", MB_OK); return NULL; } buffer[buflen] = 0; return buffer; } export void free_buffer(LPVOID buffer) { delete[] (char*) buffer; } 
  3. 让DLL使用Win32 API内存管理器动态分配缓冲区并将其返回给调用者,然后调用者可以使用相同的Win32 API内存管理器来释放它,而不必将其传回到DLL以释放它:

     #define _WIN32_WINNT 0x0500 #define _WIN32_IE 0x0500 #define CSIDL_MYMUSIC 0x000D #define CSIDL_MYVIDEO 0x000E #include "dll.h" #include <windows.h> #include <shlobj.h> #include <stdio.h> export LPCSTR desktop_directory() { wchar_t path[MAX_PATH+1] = {0}; if (SHGetFolderPathW(NULL, CSIDL_DESKTOP, NULL, 0, path) != S_OK) { MessageBoxW(NULL, L"ERROR in SHGetFolderPathW", L"TEST", MB_OK); return NULL; } MessageBoxW(NULL, path, L"TEST", MB_OK); int pathlen = lstrlenW(path); int buflen = WideCharToMultiByte(CP_UTF8, 0, path, pathlen, NULL, 0, NULL, NULL); if (buflen <= 0) { MessageBoxW(NULL, L"ERROR in WideCharToMultiByte", L"TEST", MB_OK); return NULL; } char *buffer = (char*) LocalAlloc(LMEM_FIXED, buflen+1); if (!buffer) { MessageBoxW(NULL, L"ERROR in LocalAlloc", L"TEST", MB_OK); return NULL; } buflen = WideCharToMultiByte(CP_UTF8, 0, path, pathlen, buffer, buflen, NULL, NULL); if (buflen <= 0) { LocalFree(buffer); MessageBoxW(NULL, L"ERROR in WideCharToMultiByte", L"TEST", MB_OK); return NULL; } buffer[buflen] = 0; return buffer; // caller can use LocalFree() to free it } 
  4. 让调用者在它自己的缓冲区中传递DLL的简单填充。这样,调用者可以决定分配和释放它的最佳方式:

     #define _WIN32_WINNT 0x0500 #define _WIN32_IE 0x0500 #define CSIDL_MYMUSIC 0x000D #define CSIDL_MYVIDEO 0x000E #include "dll.h" #include <windows.h> #include <shlobj.h> #include <stdio.h> // the caller can set buffer=NULL and buflen=0 to calculate the needed buffer size export int desktop_directory(LPSTR buffer, int buflen) { wchar_t path[MAX_PATH+1] = {0}; if (SHGetFolderPathW(NULL, CSIDL_DESKTOP, NULL, 0, path) != S_OK) { MessageBoxW(NULL, L"ERROR in SHGetFolderPathW", L"TEST", MB_OK); return -1; } MessageBoxW(NULL, path, L"TEST", MB_OK); int pathlen = lstrlenW(path); int len = WideCharToMultiByte(CP_UTF8, 0, path, pathlen, buffer, buflen, NULL, NULL); if (len <= 0) { MessageBoxW(NULL, L"ERROR in WideCharToMultiByte", L"TEST", MB_OK); return -1; } if (!buffer) ++len; else if (len < buflen) buffer[len] = 0; return len; }