简体   繁体   English

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

[英]Get the user's Desktop folder using Windows API?

I am trying to get the user's Desktop folder in a C++ application (via a DLL) by using SHGetSpecialFolderPath : 我试图通过使用SHGetSpecialFolderPath在C ++应用程序(通过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>

TCHAR path[MAX_PATH];

export LPSTR desktop_directory()
{

    if (SHGetSpecialFolderPath(HWND_DESKTOP, path, CSIDL_DESKTOP, FALSE)) { 
        return path;
    }

}

First I want to return an else case. 首先,我想返回一个其他案例。 I return "ERROR" but the compiler warns me that is trying to convert a CHAR to a LPSTR . 我返回“ERROR”但编译器警告我正在尝试将CHAR转换为LPSTR With that if there, it looks that the DLL might crash if it cannot get the directory for some reason. 如果有,那么如果由于某种原因它无法获取目录,它看起来可能会崩溃。

Also from the MSDN documentation, it says "[SHGetSpecialFolderPath is not supported. Instead, use ShGetFolderPath.]", then I navigate to that page and it says "ShGetFolderPath: Deprecated. Gets the path of a folder identified by a CSIDL value." 同样来自MSDN文档,它说“[SHGetSpecialFolderPath不受支持。而是使用ShGetFolderPath。]”,然后我导航到该页面,它显示“ShGetFolderPath:Deprecated。获取由CSIDL值标识的文件夹的路径。” What am I supposed to use instead? 我应该用什么呢?

So: 所以:

  1. I want to add an else case where I return a string saying "ERROR" 我想添加一个else情况,我返回一个字符串说“ERROR”
  2. I want to know if I am using the correct non-deprecated API function that will work to the modern Windows OS as far back as Windows XP. 我想知道我是否正在使用正确的非弃用API函数,该函数可以用于现代Windows操作系统,可以追溯到Windows XP。

EDIT 编辑

Here is the updated code as requested, 这是所要求的更新代码,

#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";
    }

}

Compiling with MinGW using: g++ "src\\dll\\main.cpp" -D UNICODE -D _UNICODE -O3 -DNDEBUG -s -shared -o "output\\main.dll" 使用以下命令编译MinGW: g++ "src\\dll\\main.cpp" -D UNICODE -D _UNICODE -O3 -DNDEBUG -s -shared -o "output\\main.dll"

I need to pass the string from the DLL as UTF-8 using WideCharToMultiByte(CP_UTF8, ...) , but I am not sure how to do that. 我需要使用WideCharToMultiByte(CP_UTF8, ...)将DLL中的字符串作为UTF-8 WideCharToMultiByte(CP_UTF8, ...) ,但我不知道该怎么做。

SHGetFolderPath() returns an HRESULT , where 0 is S_OK , but your code is expecting it to return a BOOL like SHGetSpecialFolderPath() does, where 0 is FALSE . SHGetFolderPath()返回一个HRESULT ,其中0是S_OK ,但是你的代码期望它返回一个像SHGetSpecialFolderPath()那样的BOOL ,其中0是FALSE So you need to fix that mistake in your code, as it is currently treating a success as if it were a failure instead. 因此,您需要在代码中修复该错误,因为它目前正在将成功视为失败。

With that said, you are returning a LPSTR from your function. 话虽如此,您将从您的函数返回LPSTR That is a char* . 这是一个char* But you are using TCHAR for your buffer. 但是您正在使用TCHAR作为缓冲区。 TCHAR maps to either char or wchar_t depending on whether UNICODE is defined or not. TCHAR映射到charwchar_t具体取决于是否定义了UNICODE So you need to decide if you want to return a char* unconditionally, or if you want to return a TCHAR* , or both. 因此,您需要决定是否要无条件地返回char* ,或者是否要返回TCHAR* ,或者两者都返回。 It makes a big difference, eg: 它有很大的不同,例如:

#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";
}

Versus: 与:

#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");
}

Versus: 与:

#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";
}

Update: most Win32 API functions do not support UTF-8, so if you want the function to return a UTF-8 string, you will have to call the Unicode flavor of the functions, and then use WideCharToMultiByte() to convert the output to UTF-8. 更新:大多数Win32 API函数不支持UTF-8,因此如果您希望函数返回UTF-8字符串,则必须调用函数的Unicode风格,然后使用WideCharToMultiByte()将输出转换为UTF-8。 But then you have a problem - who allocates and frees the UTF-8 buffer? 但是你有一个问题 - 谁分配并释放UTF-8缓冲区? There are several different ways to handle that: 有几种不同的方法来处理:

  1. use a thread-safe static buffer (but watch out for this gotcha ). 使用线程安全的静态缓冲区(但请注意这个问题 )。 If you don't need to worry about multiple threads accessing the function, then drop the __declspec(thread) specifier: 如果您不需要担心多个线程访问该函数,那么删除__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. have the DLL dynamically allocate the buffer using its own memory manager and return it to the caller, and then require the caller to pass the buffer back to the DLL when done using it so it can be freed with the DLL's memory manager: 让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. have the DLL dynamically allocate the buffer using a Win32 API memory manager and return it to the caller, and then the caller can deallocate it using the same Win32 API memory manager without having to pass it back to the DLL to free it: 让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. have the caller pass in its own buffer that the DLL simply fills in. That way, the caller can decide the best way to allocate and free it: 让调用者在自己的缓冲区中传递,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; } 

There is a better way of doing this than WidecharToMultibyte 有一种比WidecharToMultibyte更好的方法

wstring wcharthingy = wstring(widechar);
string convertedthingy = string(wcharthingy.Begin(),wcharthingy.end())

This is more pseudocode because I don't remember exactly, but Visual Studio or XCode will probably correct you anywyay. 这是更多的伪代码,因为我不记得确切,但Visual Studio或XCode可能会纠正你的任何问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 是否有任何可靠的API可以在Windows中获取Windows文件夹? - Is there any reliable API to Get Windows Folder in Windows? 使用 Windows API 的文件夹树的分层列表 - Hierarchical listing of a folder tree using Windows API 在 windows 上,是否可以在不使用 PATH 环境变量的情况下让 dll 在另一个文件夹中查找依赖项? - On windows is it possible to get dll's to look for dependencies in another folder without using the PATH environment variable? 将要漫游的用户数据文件与Windows用户的桌面设置一起放置在哪里? - Where to place user data file to be roamed along with Windows user's desktop settings? 使用内置的 Windows 方法获取文件夹的内容 - Using built in Windows Methods to get Contents of Folder 如何使用原始 Windows API 以编程方式将证书安装到用户的受信任发布者存储中? - How can I install a certificate into the user's Trusted Publishers store programmatically using raw windows API? 如何获取特定用户的Windows“特殊文件夹”的路径? - How can I get the path of a Windows “special folder” for a specific user? 如何在Windows中获取当前用户的库文件夹列表? - How to get libraries folder list in Windows for current user? 如何在 unix 和 windows 中获取系统或用户临时文件夹? - how to get system or user temp folder in unix and windows? Windows文件夹共享API - Windows Folder Share API
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM