you what visual programacion para instalar herramientas escritorio develop desarrollo con applications application aplicaciones aplicacion c++ windows winapi

c++ - what - Obtener la carpeta de escritorio del usuario con la API de Windows?



what types of windows desktop applications can you develop using c++? (2)

Estoy tratando de obtener la carpeta del escritorio del usuario en una aplicación C ++ (a través de una DLL) usando 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; } }

Primero quiero devolver un caso más. LPSTR "ERROR" pero el compilador me advierte que está tratando de convertir un CHAR a un LPSTR . Con eso, si existe, parece que la DLL podría bloquearse si no puede obtener el directorio por alguna razón.

También de la documentación de MSDN, dice "[SHGetSpecialFolderPath no es compatible. En su lugar, use ShGetFolderPath.]", Luego navego a esa página y dice "ShGetFolderPath: Deprecated. Obtiene la ruta de una carpeta identificada por un valor CSIDL". ¿Qué se supone que debo usar en su lugar?

Asi que:

  1. Quiero agregar un caso else donde devuelvo una cadena que dice "ERROR"
  2. Quiero saber si estoy usando la función correcta de API no desaprovechada que funcionará para el sistema operativo Windows moderno desde Windows XP.

EDITAR

Aquí está el código actualizado según lo solicitado,

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

Compilación con MinGW usando: g++ "src/dll/main.cpp" -D UNICODE -D _UNICODE -O3 -DNDEBUG -s -shared -o "output/main.dll"

Necesito pasar la cadena de la DLL como UTF-8 utilizando WideCharToMultiByte(CP_UTF8, ...) , pero no estoy seguro de cómo hacerlo.


SHGetFolderPath() devuelve un HRESULT , donde 0 es S_OK , pero su código espera que devuelva un BOOL como lo hace SHGetSpecialFolderPath() , donde 0 es FALSE . Por lo tanto, debe corregir ese error en su código, ya que actualmente está tratando el éxito como si fuera un error.

Dicho esto, está devolviendo un LPSTR de su función. Eso es un char* Pero estás usando TCHAR para tu buffer. TCHAR asigna a char o wchar_t dependiendo de si UNICODE está definido o no. Por lo tanto, debe decidir si desea devolver un char* incondicionalmente, o si desea devolver un TCHAR* , o ambos. Hace una gran diferencia, por ejemplo:

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

Actualización: la mayoría de las funciones API de Win32 no son compatibles con UTF-8, por lo que si desea que la función devuelva una cadena UTF-8, tendrá que llamar al sabor Unicode de las funciones y luego usar WideCharToMultiByte() para convertir la salida a UTF-8. Pero entonces tienes un problema: ¿quién asigna y libera el buffer UTF-8? Hay varias formas diferentes de manejar eso:

  1. utilice un buffer estático seguro para subprocesos (pero cuidado con este gotcha ). Si no necesita preocuparse de que varios subprocesos accedan a la función, elimine el __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. haga que la DLL asigne dinámicamente el búfer usando su propio administrador de memoria y devuélvalo a la persona que llama, y ​​luego solicite que la persona que llama pase el búfer a la DLL cuando termine de usarlo para que pueda ser liberado con el administrador de memoria de la 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. haga que la DLL asigne dinámicamente el búfer utilizando un administrador de memoria Win32 API y devuélvala a la persona que llama, y ​​luego la persona que llama puede desasignarlo utilizando el mismo administrador de memoria Win32 API sin tener que volver a pasarlo a la DLL para liberarlo:

    #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. haga que la persona que llama pase su propio búfer que simplemente llena el archivo DLL. De esta forma, quien llama puede decidir la mejor manera de asignarlo y liberarlo:

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


Hay una forma mejor de hacer esto que WidecharToMultibyte

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

Esto es más pseudocódigo porque no recuerdo exactamente, pero Visual Studio o XCode probablemente lo corregirán de todos modos.