问题描述
我试图通过使用 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路径[MAX_PATH];
export LPSTR desktop_directory()
{
if(SHGetSpecialFolderPath(HWND_DESKTOP,path,CSIDL_DESKTOP,FALSE)){
return path;
}
}
首先我要返回一个else案件。我返回错误,但编译器警告我,试图将 CHAR
转换为 LPSTR
。如果有的话,它看起来DLL可能会崩溃,如果它不能得到的目录由于某种原因。
也从MSDN文档,它说[SHGetSpecialFolderPath不是支持,而是使用ShGetFolderPath。],然后我导航到该页面,并说ShGetFolderPath:Deprecated。获取由CSIDL值标识的文件夹的路径。
因此:
- 添加一个else case,我返回一个字符串ERROR
我想知道如果我使用正确的非过时的API函数,将工作到现代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
#includedll.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,LTEST,MB_OK); // test
return path;
} else {
return LERROR;
}
}
使用MinGW编译: g ++src\dll\main.cpp-D UNICODE -D _UNICODE -O3 -DNDEBUG -s -shared -ooutput\main.dll
我需要使用 WideCharToMultiByte(CP_UTF8,...)
从UTF-8的DLL传递字符串,不知道该怎么做。
CSIDL_DESKTOP
一个文件系统路径,所以你不能使用它与 SHGetSpecialFolderPath()
和相关的功能。它是一个虚拟文件夹,它是Shell命名空间中其他文件夹的根。
如果您正在查找文件夹的实际文件系统路径,用户的桌面,则需要使用 CSIDL_DESKTOPDIRECTORY
。
$ c> LPSTR 。这是一个 char *
。但是你使用 TCHAR
作为缓冲区。 TCHAR
映射到 char
或 wchar_t
code> UNICODE 是否定义。因此,您需要决定是否要无条件地返回 char *
,或者如果要返回 TCHAR *
, 或两者。它有很大的区别,例如:
#define _WIN32_WINNT 0x0500
#define _WIN32_IE 0x0500
#define CSIDL_MYMUSIC 0x000D
#define CSIDL_MYVIDEO 0x000E
#includedll.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_DESKTOPDIRECTORY,FALSE))
返回路径;
else
returnERROR;
}
相对:
#define _WIN32_WINNT 0x0500
#define _WIN32_IE 0x0500
#define CSIDL_MYMUSIC 0x000D
#define CSIDL_MYVIDEO 0x000E
#includedll .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_DESKTOPDIRECTORY,FALSE))
返回路径;
else
return TEXT(ERROR);
}
相对:
#define _WIN32_WINNT 0x0500
#define _WIN32_IE 0x0500
#define CSIDL_MYMUSIC 0x000D
#define CSIDL_MYVIDEO 0x000E
#includedll .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_DESKTOPDIRECTORY,FALSE))
返回路径;
else
返回ERROR;
}
export LPWSTR desktop_directory_unicode()
{
static wchar_t path [MAX_PATH + 1];
if(SHGetSpecialFolderPathW(HWND_DESKTOP,path,CSIDL_DESKTOPDIRECTORY,FALSE))
返回路径;
else
return LERROR;
}
更新:大多数Win32 API函数不支持UTF-8,所以如果你想让函数返回一个UTF-8字符串,你必须调用Unicode风格的函数,并使用 WideCharToMultiByte()
输出到UTF-8。但是,然后你有一个问题 - 谁分配和释放UTF-8缓冲区?有几种不同的方法来处理:
-
使用线程安全的静态缓冲区(但要注意)。如果你不需要担心多线程访问函数,那么请删除
__ 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 [ (NULL,L); $ MAX_PATH + 1] = {0};
if(SHGetFolderPathW(NULL,CSIDL_DESKTOPDIRECTORY,NULL,0,path)!= S_OK)
{
MessageBoxW ERROR in SHGetFolderPathW,LTEST,MB_OK);
return NULL;
}
MessageBoxW(NULL,path,LTEST,MB_OK);
int buflen = WideCharToMultiByte(CP_UTF8,0,path,lstrlenW(path),desktop_dir_buffer,MAX_PATH * 4,NULL,NULL);
if(buflen {
MessageBoxW(NULL,LERROR in WideCharToMultiByte,LTEST,MB_OK);
return NULL;
}
desktop_dir_buffer [buflen] = 0;
return desktop_dir_buffer;
}
-
动态分配缓冲区并将其返回给调用者,但是使用DLL自己的内存管理器分配它,这将要求调用者将缓冲区传递回DLL,以便在调用者使用它时释放它:
#define _WIN32_WINNT 0x0500
#define _WIN32_IE 0x0500
#define CSIDL_MYMUSIC 0x000D
#define CSIDL_MYVIDEO 0x000E
#includedll.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_DESKTOPDIRECTORY,NULL,0,path)!= S_OK)
{
MessageBoxW(NULL,LSHGetFolderPathW中的错误,LTEST ,MB_OK);
return NULL;
}
MessageBoxW(NULL,path,LTEST,MB_OK);
int pathlen = lstrlenW(path);
int buflen = WideCharToMultiByte(CP_UTF8,0,path,pathlen,NULL,0,NULL,NULL);
if(buflen {
MessageBoxW(NULL,LWideCharToMultiByte,LTEST,MB_OK中的ERROR);
return NULL;
}
char * buffer = new char [buflen + 1];
buflen = WideCharToMultiByte(CP_UTF8,0,path,pathlen,buffer,buflen,NULL,NULL);
if(buflen {
delete [] buffer;
MessageBoxW(NULL,LERROR in WideCharToMultiByte,LTEST,MB_OK);
return NULL;
}
buffer [buflen] = 0;
返回缓冲区;
}
export void free_buffer(LPVOID buffer)
{
delete [](char *)buffer;
}
-
让动态分配缓冲区并返回给调用者,但是使用Win32 API内存管理器分配它,以便调用者可以使用Win32 API释放它,而不将其传递回DLL来释放它:
#define _WIN32_WINNT 0x0500
#define _WIN32_IE 0x0500
#define CSIDL_MYMUSIC 0x000D
#define CSIDL_MYVIDEO 0x000E
#includedll.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_DESKTOPDIRECTORY,NULL,0,path)!= S_OK)
{
MessageBoxW(NULL,LSHGetFolderPathW中的错误,LTEST ,MB_OK);
return NULL;
}
MessageBoxW(NULL,path,LTEST,MB_OK);
int pathlen = lstrlenW(path);
int buflen = WideCharToMultiByte(CP_UTF8,0,path,pathlen,NULL,0,NULL,NULL);
if(buflen {
MessageBoxW(NULL,LWideCharToMultiByte,LTEST,MB_OK中的ERROR);
return NULL;
}
char * buffer =(char *)LocalAlloc(LMEM_FIXED,buflen + 1);
if(!buffer)
{
MessageBoxW(NULL,LLocalAlloc中的错误,LTEST,MB_OK);
return NULL;
}
buflen = WideCharToMultiByte(CP_UTF8,0,path,pathlen,buffer,buflen,NULL,NULL);
if(buflen {
LocalFree(buffer);
MessageBoxW(NULL,LERROR in WideCharToMultiByte,LTEST,MB_OK);
return NULL;
}
buffer [buflen] = 0;
返回缓冲区; //调用者可以使用LocalFree()来释放它
}
-
调用者可以决定分配和释放它的最佳方式:
#define _WIN32_WINNT 0x0500
#define _WIN32_IE 0x0500
#define CSIDL_MYMUSIC 0x000D
#define CSIDL_MYVIDEO 0x000E
#includedll.h
#include< windows.h>
#include< shlobj.h>
#include< stdio.h>
//调用者可以设置buffer = NULL和buflen = 0来计算所需的缓冲区大小
export int desktop_directory(LPSTR buffer,int buflen)
{
wchar_t path [MAX_PATH + 1] = {0};
if(SHGetFolderPathW(NULL,CSIDL_DESKTOPDIRECTORY,NULL,0,path)!= S_OK)
{
MessageBoxW(NULL,LSHGetFolderPathW中的错误,LTEST ,MB_OK);
return -1;
}
MessageBoxW(NULL,path,LTEST,MB_OK);
int pathlen = lstrlenW(path);
int len = WideCharToMultiByte(CP_UTF8,0,path,pathlen,buffer,buflen,NULL,NULL);
if(len< = 0)
{
MessageBoxW(NULL,LWideCharToMultiByte,LTEST,MB_OK中的ERROR);
return -1;
}
if(!buffer)
++ len;
else if(len< buflen)
buffer [len] = 0;
return len;
}
I am trying to get the user's Desktop folder in a C++ application (via a DLL) by using SHGetSpecialFolderPath
:
#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
. 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." What am I supposed to use instead?
So:
- I want to add an else case where I return a string saying "ERROR"
- 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.
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"
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.
CSIDL_DESKTOP
does not have a file system path, so you can't use it with SHGetSpecialFolderPath()
and related functions. It is a virtual folder that is the root for other folders in the Shell namespace.
If you are looking for the actual file system path of the folder that holds files on the user's Desktop, then you need to use CSIDL_DESKTOPDIRECTORY
instead.
With that said, you are returning a LPSTR
from your function. That is a char*
. But you are using TCHAR
for your buffer. TCHAR
maps to either char
or wchar_t
depending on whether UNICODE
is defined or not. So you need to decide if you want to return a char*
unconditionally, or if you want to return a TCHAR*
, or both. 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_DESKTOPDIRECTORY, 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_DESKTOPDIRECTORY, 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_DESKTOPDIRECTORY, FALSE))
return path;
else
return "ERROR";
}
export LPWSTR desktop_directory_unicode()
{
static wchar_t path[MAX_PATH+1];
if (SHGetSpecialFolderPathW(HWND_DESKTOP, path, CSIDL_DESKTOPDIRECTORY, FALSE))
return path;
else
return L"ERROR";
}
Update: most Win32 API functions do not support UTF-8, so if you want the function return a UTF-8 string, you will have to call the Unicode flavor of the functions, and use WideCharToMultiByte()
to convert the output to UTF-8. But then you have a problem - who allocates and frees the UTF-8 buffer? There are several different ways to handle that:
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)
portion:#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; }
have the DLL dynamically allocate the buffer and return it to the caller, but allocate it with the DLL's own memory manager, which would require the caller to pass the buffer back to the DLL to free it when the caller is done using it:
#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_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 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; }
have the DLL dynamically allocate the buffer and return it to the caller, but allocate it with the Win32 API memory manager so that the caller can deallocate it using the Win32 API and not pass it back to the DLL to free it:
#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_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 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 }
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:
#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_DESKTOPDIRECTORY, 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; }
这篇关于使用Windows API获取用户的Desktop文件夹?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!