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

问题描述 投票:8回答:2

我试图通过使用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。如果有,那么如果由于某种原因它无法获取目录,它看起来可能会崩溃。

同样来自MSDN文档,它说“[SHGetSpecialFolderPath不受支持。而是使用ShGetFolderPath。]”,然后我导航到该页面,它显示“ShGetFolderPath:Deprecated。获取由CSIDL值标识的文件夹的路径。”我应该用什么呢?

所以:

  1. 我想添加一个else情况,我返回一个字符串说“ERROR”
  2. 我想知道我是否正在使用正确的非弃用API函数,该函数可以用于现代Windows操作系统,可以追溯到Windows XP。

编辑

这是所要求的更新代码,

#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, ...)将DLL中的字符串作为UTF-8传递,但我不知道该怎么做。

c++ windows winapi
2个回答
10
投票

SHGetFolderPath()返回一个HRESULT,其中0是S_OK,但是你的代码期望它返回像BOOL那样的SHGetSpecialFolderPath(),其中0是FALSE。因此,您需要在代码中修复该错误,因为它目前正在将成功视为失败。

话虽如此,你将从你的功能返回一个LPSTR。这是一个char*。但是你使用TCHAR作为你的缓冲区。 TCHAR根据char是否定义,映射到wchar_tUNICODE。所以你需要决定是否要无条件地返回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. 使用线程安全的静态缓冲区(但要注意this gotcha)。如果您不需要担心访问该函数的多个线程,请删除__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的内存管理器释放它: #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; }

-1
投票

有一个比WidecharToMultibyte更好的方法

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

这是更多的伪代码,因为我不记得确切,但Visual Studio或XCode可能会纠正你的任何问题。

© www.soinside.com 2019 - 2024. All rights reserved.