malloc
malloc

Reputation: 684

How to feed SHGetKnownFolderPath output to CopyFile in C++?

I want to get FOLDERID_ProgramFiles by SHGetKnownFolderPath and copy current running file to it by this code:

char ModuleFileName[24];
GetModuleFileName(NULL, ModuleFileName, MAX_PATH) ;

PWSTR path = NULL;
SHGetKnownFolderPath(FOLDERID_ProgramFiles,0,NULL,&path);

CopyFile(ModuleFileName,path,FALSE);

But i had no lock because , PWSTR is a wchar_t* and CopyFile needs const char* , I have tried to put star before Path and convert it by using wcstombs function but no lock!

How can i fix it?

PS: I've got this error:

error: cannot convert ‘PWSTR {aka wchar_t*}’ to ‘LPCSTR {aka const char*}’ for argument ‘2’ to ‘WINBOOL CopyFileA(LPCSTR, LPCSTR, WINBOOL)’

And i should mention I'am using Mingw g++ compiler so printing out these variable is a bit challenging by using wprintf(L"%ls\n",[STR] ); and i get a lot of bad chars in output.

Upvotes: 0

Views: 457

Answers (2)

Remy Lebeau
Remy Lebeau

Reputation: 596041

You are calling the ANSI version of CopyFile() and passing it a Unicode string in the second parameter. That is why you are getting a compiler error. Use the Unicode version of GetModuleFileName() and CopyFile() instead.

Also, your ModuleFileName is only 24 chars in size, but you are telling GetModuleFileNameW() that it is MAX_PATH (260) chars in size.

Also, CopyFile() expects file paths, not folder paths. You need to extract the filename from ModuleFileName and append it to the end of path when passing it to the 2nd parameter.

Try something more like this:

WCHAR ModuleFileName[MAX_PATH] = {};
GetModuleFileNameW(NULL, ModuleFileName, MAX_PATH);

PWSTR path = NULL;
SHGetKnownFolderPath(FOLDERID_ProgramFiles, 0, NULL, &path);

WCHAR NewFileName[MAX_PATH] = {};
PathCombineW(NewFileName, path, PathFindFileNameW(ModuleFileName));

CoTaskMemFree(path);

CopyFileW(ModuleFileName, NewFileName, FALSE);

There are other alternatives to PathCombine(), eg:

WCHAR NewFileName[PATHCCH_MAX_CCH] = {};
PathCchCombine(NewFileName, PATHCCH_MAX_CCH, path, PathFindFileNameW(ModuleFileName));
// use NewFileName as needed...
PWSTR NewFileName = NULL;
PathAllocCombine(path, PathFindFileNameW(ModuleFileName), 0, &NewFileName);
// use NewFileName as needed...
LocalFree(NewFileName);
#include <string>
std::wstring NewFileName(path);
if (NewFileName.back() != L'\\')
    NewFileName += L'\\';
NewFileName += PathFindFileNameW(ModuleFileName);
// use NewFileName as needed...
#include <filesystem>
std::wstring NewFileName = (std::filesystem::path(path) / PathFindFileNameW(ModuleFileName)).wstring();
// use NewFileName as needed...

Upvotes: 2

SoronelHaetir
SoronelHaetir

Reputation: 15162

Use the *W variants of the API functions (GetModuleFileNameW, CopyFileW etc) and use wchar_t characters rather than char throughout.

Your other option would be to take the returned path from SHGetKnownFolderPath and use WideCharToMultiByte to translate the path to chars but the first way is much preferable (it doesn't dpend on the characters matching the user locale for example).

Upvotes: 4

Related Questions