change the use of SHBrowseForFolder and struct BROWSEINFO TO - IFileOpenDialog - c++

until now- in order to open a dialog box I used SHBrowseForFolder function. It causes some bugs and I was told to use IFileOpenDialog.
here is the code I need to replace:
bool wvFM::SelectFileSystemObjectDialogTree(const WCDialogCreationOptions& in_options,
WCDialogReply& out_Reply)
{
AUTO_FUNC_DEBUG;
DWORD osErr = NO_ERROR;
WTErr wtErr = eNoErr;
out_Reply.accept = false;
if(in_options.m_flags[WCDialogCreationOptions::eSelectFolder]) {
BROWSEINFO bi = {0};
bi.hwndOwner = (HWND)in_options.m_owner;
bi.pidlRoot = NULL; // TBD by callback BrowseCallbackProc
bi.lpszTitle = in_options.m_windowTitle.c_str();
bi.ulFlags = BIF_USENEWUI; // to enable pasting path
bi.lpfn = BrowseCallbackProc; // for initial dir option
WTPathString initialLocationPathString(
in_options.m_InitialDir.GetNativePathString());
bi.lParam = in_options.m_InitialDir.IsValid()
? (LPARAM)initialLocationPathString.c_str()
: NULL;
LPITEMIDLIST pidl = SHBrowseForFolder(&bi);
// returns focus to the internal window of the plug
::SetFocus((HWND)in_options.m_owner);
if(pidl != NULL) {
TCHAR szPath[MAX_PATH];
SHGetPathFromIDList(pidl, szPath);
out_Reply.m_filePathRef = wvFM::WCStPath((char*)szPath);
out_Reply.accept = true;
IMalloc* imalloc = 0;
if(SUCCEEDED(SHGetMalloc(&imalloc))) {
imalloc->Free(pidl);
imalloc->Release();
}
}
return true;
}
I am not so sure of how to make that conversion.
Thanks to anyone who will help!

You are clearly using a 3rd party library with some kind of custom string type, but you did not provide any details about what that string type actually is. I'm guessing that string type is char-based, given that you are type-casting the result of SHGetPathFromIDList() to char* when assigning it to out_Reply.m_filePathRef, so you are likely compiling your project with UNICODE undefined so that TCHAR maps to char and not wchar_t. In which case, SHBrowseForFolder() would be calling SHBrowseForFolderA() and not SHBrowseForFolderW().
IFileOpenDialog does not deal with ANSI strings at all, only UNICODE strings, so you will have to convert back and forth between your 3rd party string type and Windows UTF-16 strings as needed.
The conversion of SHBrowseForFolder() to IFileOpenDialog would look roughly like the following (where YourStringType in toWString() is the 3rd party string type - make whatever adjustments you need where indicated):
std::wstring toWString(const YourStringType &str)
{
const char pStr = ... pointer to str's characters ...;
int sLen = ... length of str in chars, not counting the null terminator ...;
std::wstring ws;
int wLen = MultiByteToWideChar(CP_ACP, 0, pStr, slen, NULL, 0);
if (wLen > 0)
{
ws.resize(wLen);
MultiByteToWideChar(CP_ACP, 0, pStr, sLen, ws.data(), wLen);
}
return ws;
}
std::string toString(const wchar_t *ws)
{
std::string s;
int wLen = lstrlenW(s);
int sLen = WideCharToMultiByte(CP_ACP, 0, ws, wLen, NULL, 0, NULL, NULL);
if (sLen > 0)
{
s.resize(sLen);
WideCharToMultiByte(CP_ACP, 0, ws, wLen, s.data(), sLen, NULL, NULL);
}
return s;
}
IShellItem* toShellItem(const YourStringType &path)
{
IShellItem *pItem = NULL;
if (FAILED(SHCreateItemFromParsingName(toWString(path).c_str(), NULL, IID_PPV_ARGS(&pItem))))
pItem = NULL;
return pItem;
}
bool wvFM::SelectFileSystemObjectDialogTree(const WCDialogCreationOptions& in_options,
WCDialogReply& out_Reply)
{
AUTO_FUNC_DEBUG;
out_Reply.accept = false;
if (in_options.m_flags[WCDialogCreationOptions::eSelectFolder]) {
IFileOpenDialog *pFileOpen = NULL;
if (FAILED(CoCreateInstance(CLSID_FileOpenDialog, NULL, CLSCTX_ALL, IID_PPV_ARGS(&pFileOpen))))
return false;
FILEOPENDIALOGOPTIONS opts = 0;
pFileOpen->GetOptions(&opts);
pFileOpen->SetTitle(toWString(in_options.m_windowTitle).c_str());
pFileOpen->SetOptions(opts | FOS_PICKFOLDERS);
IShellItem *pItem = toShellItem(in_options.m_InitialDir);
if (pItem)
{
pFileOpen->SetFolder(pItem);
pItem->Release();
}
HWND hwndOwner = (HWND) in_options.m_owner;
HRESULT hr = pFileOpen->Show(hwndOwner);
::SetFocus(hwndOwner);
if (SUCCEEDED(hr))
{
if (SUCCEEDED(pFileOpen->GetResult(&pItem)))
{
PWSTR pszFilePath;
if (SUCCEEDED(pItem->GetDisplayName(SIGDN_FILESYSPATH, &pszFilePath)))
{
out_Reply.m_filePathRef = wvFM::WCStPath(toString(pszFilePath).c_str());
out_Reply.accept = true;
CoTaskMemFree(pszFilePath);
}
pItem->Release();
}
}
pFileOpen->Release();
return true;
}
...
}

Related

Win32 CryptProtectData how to save output data?

https://learn.microsoft.com/en-us/windows/win32/api/dpapi/nf-dpapi-cryptprotectdata
How can I save the output key to the windows registry or a file? I've been trying to do this for two days now but no progress. One of the problems is that I am using Unreal Engine and they have their own string type "FString" which does not easily convert to std::string or const char*
This is the code I'm using to save to the registry, but I'm not sure if it's valid:
void SUGH1LoginWidget::SecureSaveJWTToken(FString JWT_Token)
{
#ifdef _WIN32
DATA_BLOB DataIn;
DATA_BLOB DataOut; // Key to decrypt the data. Store in windows registry.
DATA_BLOB EncryptionKey; // Uses define in ShooterGame.h to encrypt the data so that only the UGH1 application can access the token.
DWORD cbDataInput = lstrlenA((char*)TCHAR_TO_ANSI(*JWT_Token)) + 1;
DataIn.pbData = (BYTE*)ConvertFStringToCString(JWT_Token).get();
DataIn.cbData = cbDataInput;
BYTE* pbDataEncryptionKey = (BYTE*)TOKEN_ENCRYPTION_KEY;
DWORD cbDataEncryptionKey = strlen((char*)pbDataEncryptionKey) + 1;
EncryptionKey.pbData = pbDataEncryptionKey;
EncryptionKey.cbData = cbDataEncryptionKey;
// Finally save the data
CryptProtectData(&DataIn, NULL, &EncryptionKey, NULL, NULL, NULL, &DataOut);
SaveJWTDecryptionKeyToRegistry(DataOut);
#endif
}
void SUGH1LoginWidget::SaveJWTDecryptionKeyToRegistry(DATA_BLOB DecryptionKey)
{
FString Base64EncryptionKey = FBase64::Encode(DecryptionKey.pbData, DecryptionKey.cbData);
HKEY CurrentUserKey;
LSTATUS Error;
Error = RegOpenCurrentUser(KEY_ALL_ACCESS, &CurrentUserKey);
if (Error == ERROR_SUCCESS)
{
HKEY SoftwareKey;
Error = RegOpenKeyExA(CurrentUserKey, "SOFTWARE", NULL, KEY_WRITE, &SoftwareKey);
if (Error == ERROR_SUCCESS)
{
HKEY UGHStudiosSubKey;
Error = RegCreateKeyExA(SoftwareKey, "UGH Studios LLC", NULL, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &UGHStudiosSubKey, NULL);
if (Error == ERROR_SUCCESS)
{
Error = RegSetValueExA(UGHStudiosSubKey, "LoginTokenDecryptionKey", NULL, REG_SZ, (BYTE*)TCHAR_TO_ANSI(*Base64EncryptionKey), Base64EncryptionKey.Len());
RegCloseKey(UGHStudiosSubKey);
RegCloseKey(SoftwareKey);
if (Error != ERROR_SUCCESS)
{
UE_LOG(LogLoginWidget, Error, TEXT("The game was unable to save the login token to the registry."));
}
}
}
}
else
{
UE_LOG(LogLoginWidget, Error, TEXT("The game was unable to access the windows registry on this machine. "));
}
RegCloseKey(CurrentUserKey);
}
This is my code for loading from the registry back into an FString but it's not working properly:
std::shared_ptr<char[]> SUGH1LoginWidget::ConvertFStringToCString(const FString InputString)
{
std::shared_ptr<char[]> ptr(new char[InputString.Len()]);
TArray<TCHAR> CharArray = InputString.GetCharArray();
for (int i = 0; i < InputString.Len(); i++)
{
ptr[i] = CharArray[i];
}
return ptr;
}
PRAGMA_DISABLE_OPTIMIZATION
FReply SUGH1LoginWidget::GetJWTTokenFromRegistry()
{
TArray<uint8> DecryptionKeyBytes;
// load base64 string from registry
LSTATUS Error;
HKEY UGHStudiosSubKey;
Error = RegOpenKeyExA(HKEY_CURRENT_USER, "SOFTWARE\\UGH Studios LLC", NULL, KEY_READ, &UGHStudiosSubKey);
if (Error == ERROR_SUCCESS)
{
char buffer[8193] = { 0 };
DWORD dwLen = 8192;
DWORD dwType = 0;
Error = RegQueryValueExA(UGHStudiosSubKey, "LoginTokenDecryptionKey", 0, &dwType, (BYTE*)buffer, &dwLen);
if (Error == ERROR_SUCCESS)
{
std::string outValue = buffer;
FString decoded_string;
//FString reg_value_as_fstring = FString(outValue.length(), outValue.c_str());
uint8* decoded = malloc();
FBase64::Decode(outValue.c_str(), outValue.size(), decoded);
//:Decode(const FString & Source, TArray<uint8>&OutDest
//::Decode(const CharType* Source, uint32 Length, uint8* Dest)
//UE_LOG(LogLoginWidget, Error, TEXT("Out value: %s"), *decoded_string);
}
//Error = RegQueryValueExA(UGHStudiosSubKey, "LoginTokenDecryptionKey", NULL, NULL, buffer, size);
return FReply::Handled();
//return decoded_string;
//std::string outvalue = (char*)buffer;
}
//FBase64::Decode(, DecryptionKeyBytes)
//return FString("");
return FReply::Handled();
}
PRAGMA_ENABLE_OPTIMIZATION
What's the standard way of saving the struct data? I was tying to Base64 encrypt it and save it as a registry key. But this doesn't work.

_wfopen_s returning 2 different outputs with 2 identicle inputs

When I feed _wfopen_s the exact same string, one a literal, one set at runtime, the literal succeeds, the string set at runtime returns error 2 (File or Directory not found)
When I look at "buff" and "bufftwo" in the visual studio debugger, they contain the exact same values, the only thing different are the addresses.
The order of 2 buffers does not change the outcome
.
It is not file, directory or drive specific.
I have tried removing const from my methods and variables, error still occurs.
wchar_t* loadFileDialog() { //https://learn.microsoft.com/en-us/windows/desktop/learnwin32/example--the-open-dialog-box
wchar_t buffer[255];
HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
if (SUCCEEDED(hr))
{
IFileOpenDialog *pFileOpen;
// Create the FileOpenDialog object.
hr = CoCreateInstance(CLSID_FileOpenDialog, NULL, CLSCTX_ALL,
IID_IFileOpenDialog, reinterpret_cast<void**>(&pFileOpen));
if (SUCCEEDED(hr))
{
// Show the Open dialog box.
hr = pFileOpen->Show(NULL);
// Get the file name from the dialog box.
if (SUCCEEDED(hr))
{
IShellItem *pItem;
hr = pFileOpen->GetResult(&pItem);
if (SUCCEEDED(hr))
{
PWSTR pszFilePath;
hr = pItem->GetDisplayName(SIGDN_FILESYSPATH, &pszFilePath);
// Display the file name to the user.
if (SUCCEEDED(hr))
{
lstrcpyW(buffer, pszFilePath); //Convert PWSTR into wchar array
CoTaskMemFree(pszFilePath);
}
pItem->Release();
}
}
pFileOpen->Release();
}
CoUninitialize();
}
return buffer;
}
/*Loads a file into memory.*/
char* loadFile(const wchar_t* filePath) {
FILE *f;
BOOL err = _wfopen_s(&f, filePath, L"rb");
if (err == 0) {
fseek(f, 0, SEEK_END);
long fsize = ftell(f);
fseek(f, 0, SEEK_SET);
char *buff= (char *)malloc(fsize + 1);
fread(buff, fsize, 1, f);
fclose(f);
buff[fsize] = 0;
return buff;
}
else {
//Outputs Err2, File not found.
throw std::runtime_error("error"); //Just here as a breakpoint until I make a better solution
}
}
int main() {
const wchar_t* bufftwo = loadFileDialog(); //Open Dialog Box
const wchar_t* buff = L"C:\\Windows\\notepad.exe";
if (lstrcmpW(bufftwo, buff) != 0) { //Here for testing, ensures both strings are identical.
throw std::runtime_error("STRINGS ARE NOT THE SAME");
}
const char* myFile;
myFile= loadFile(bufftwo);
myFile= loadFile(buff);
}
I expected loadFile(bufftwo) and loadFile(buff) to return the same value, as they have identical inputs, however loadFile(bufftwo) errors, whilst loadFile(buff) does not.

Crash Dump generation and analysis issues

I used the example from https://github.com/hdeldar/QtCrashDumper and made us of the same in my application. Lately for actual crashes in the application the stack trace has been a little useless.
Another question is the dmp files generated module version does not match. I have double checked the module version and it is the same however the dump file has different versions. File version is 2.8.0.4 and the dmp file has 2.08.0.4
I have looked into a few answers on stackoverflow to not understand what functions I am missing.
CrashDump Info
The KB link does not exist anymore - KB313109
My implementation
#include "CrashDumpDef.h"
#include "version.h"
#ifdef USE_MINI_DUMP
#include "CrashDump.h"
#include "FileSystem.h"
LPCWSTR CrashDump::m_szAppName;
LPWSTR CrashDump::m_szAppVersion;
LPWSTR CrashDump::m_szAppBuildNumber;
WCHAR CrashDump::m_szMessageText[MAX_WARNING_MESSAGE_PATH];
LPWSTR CrashDump::m_szDumpFilePath;
#define DEFAULT_MESSAGE_TEXT L"%s Designer has experienced an issue. \nCrash dump has been saved in %s."
#define MAX_DUMP_FILE_NUMBER 9999
CrashDump::CrashDump(LPCWSTR szAppName, LPCWSTR szVersion, LPCWSTR szBuildNumber)
{
// if this assert fires then you have two instances of CrashDump
// which is not allowed
Q_ASSERT(m_szAppName == NULL);
const char* sz = VER_PRODUCTVERSION_STR;
std::vector<wchar_t> vec;
size_t len = strlen(sz);
vec.resize(len + 1);
mbstowcs(&vec[0], sz, len);
const wchar_t* productVersion = &vec[0];
std::string version = VER_PRODUCTVERSION_STR;
char build = version.back();
const char* buildNum = new char(build);
std::vector<wchar_t> vec1;
size_t lenA = strlen(buildNum);
vec1.resize(lenA + 1);
mbstowcs(&vec1[0], buildNum, lenA);
const wchar_t* buildNumber = &vec1[0];
m_szAppName = szAppName ? wcsdup(szAppName) : wcsdup(L"Designer");
m_szAppVersion = productVersion ? wcsdup(productVersion) : wcsdup(productVersion);
m_szAppBuildNumber = buildNumber ? wcsdup(buildNumber) : wcsdup(buildNumber);
wcscpy(m_szMessageText, DEFAULT_MESSAGE_TEXT);
m_szDumpFilePath = NULL;
::SetUnhandledExceptionFilter(TopLevelFilter);
}
CrashDump::~CrashDump()
{
}
void CrashDump::SetVersion(LPCWSTR szVersion)
{
if (szVersion)
{
free(m_szAppVersion);
m_szAppVersion = wcsdup(szVersion);
}
}
void CrashDump::SetBuildNumber(LPCWSTR szBuildNumber)
{
if (szBuildNumber)
{
free(m_szAppBuildNumber);
m_szAppBuildNumber = wcsdup(szBuildNumber);
}
}
void CrashDump::SetDumpFilePath(LPCWSTR szFilePath)
{
free(m_szDumpFilePath);
{
m_szDumpFilePath = wcsdup(szFilePath);
}
}
LONG CrashDump::TopLevelFilter(struct _EXCEPTION_POINTERS *pExceptionInfo)
{
//::MessageBoxW(NULL, L"debugging", m_szAppName, MB_OK);
LONG retval = EXCEPTION_CONTINUE_SEARCH;
HWND hParent = NULL; // find a better value for your app
// firstly see if dbghelp.dll is around and has the function we need
// look next to the EXE first, as the one in System32 might be old
// (e.g. Windows 2000)
HMODULE hDll = NULL;
WCHAR szDbgHelpPath[_MAX_PATH];
if (GetModuleFileName(NULL, szDbgHelpPath, _MAX_PATH))
{
WCHAR *pSlash = wcsrchr(szDbgHelpPath, L'\\');
if (pSlash)
{
wcscpy(pSlash + 1, L"DBGHELP.DLL");
hDll = ::LoadLibrary(szDbgHelpPath);
}
}
if (hDll == NULL)
{
// load any version we can
hDll = ::LoadLibrary(L"DBGHELP.DLL");
}
LPCWSTR szResult = NULL;
if (hDll)
{
MINIDUMPWRITEDUMP pDump = (MINIDUMPWRITEDUMP)::GetProcAddress(hDll, "MiniDumpWriteDump");
if (pDump)
{
WCHAR szDumpPath[_MAX_PATH];
WCHAR szDumpRootPath[_MAX_PATH];
WCHAR szScratch[_MAX_PATH];
// work out a good place for the dump file - add the path here
if (m_szDumpFilePath == NULL)
{
if (GetModuleFileName(NULL, szDbgHelpPath, _MAX_PATH))
{
WCHAR *pSlash = wcsrchr(szDbgHelpPath, L'\\');
if (pSlash)
{
wcscpy(pSlash + 1, L"");
wcscpy(szDumpPath, szDbgHelpPath);
}
}
//else if (!GetTempPath(_MAX_PATH, szDumpPath))
std::string dmpFile = filesystem::buildFilename(QStringList()
<< QDir::toNativeSeparators(QDir::homePath()) + "\\AppData\\Roaming\\ABC\\logs\\"
).toStdString();
std::wstring wideDmpFile;
for (int i = 0; i < dmpFile.length(); ++i)
wideDmpFile += wchar_t(dmpFile[i]);
const wchar_t* szName = wideDmpFile.c_str();
wcscpy(szDumpPath, szName);
}
else
{
wcscpy(szDumpPath, m_szDumpFilePath);
}
wcscpy(szDumpRootPath, szDumpPath);
//PrintDebug(L"[CrashDump] Mini Dump file:[%s]",szDumpPath);
// ask the user if they want to save a dump file
//if (::MessageBox( NULL, _T("Crash, would you like to save a diagnostic file?"), m_szAppName, MB_YESNO )==IDYES)
{
HANDLE hFile = INVALID_HANDLE_VALUE;
int i = 1;
WCHAR szFileNumber[_MAX_PATH];
while (hFile == INVALID_HANDLE_VALUE)
{
swprintf(szFileNumber, sizeof(szFileNumber), L"_%04d", i);
wcscpy(szDumpPath, szDumpRootPath);
wcscat(szDumpPath, m_szAppName);
wcscat(szDumpPath, L"_");
wcscat(szDumpPath, m_szAppVersion);
wcscat(szDumpPath, L"_");
wcscat(szDumpPath, m_szAppBuildNumber);
wcscat(szDumpPath, szFileNumber);
wcscat(szDumpPath, L".dmp");
hFile = ::CreateFile(szDumpPath, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_NEW,
FILE_ATTRIBUTE_NORMAL, NULL);
i++;
if (i > MAX_DUMP_FILE_NUMBER)
{
hFile = ::CreateFile(szDumpPath, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL, NULL);
break;
}
}
// create the file
if (hFile != INVALID_HANDLE_VALUE)
{
_MINIDUMP_EXCEPTION_INFORMATION ExInfo;
ExInfo.ThreadId = ::GetCurrentThreadId();
ExInfo.ExceptionPointers = pExceptionInfo;
ExInfo.ClientPointers = NULL;
// write the dump
BOOL bOK = pDump(GetCurrentProcess(), GetCurrentProcessId(), hFile, MiniDumpNormal, &ExInfo, NULL, NULL);
if (bOK)
{
swprintf(szScratch, sizeof(szScratch), L"Saved dump file to '%s'", szDumpPath);
szResult = szScratch;
retval = EXCEPTION_EXECUTE_HANDLER;
}
else
{
swprintf(szScratch, sizeof(szScratch), L"Failed to save dump file to '%s' (error %d)", szDumpPath, GetLastError());
szResult = szScratch;
}
::CloseHandle(hFile);
WCHAR csOutMessage[MAX_WARNING_MESSAGE_PATH];
swprintf(csOutMessage, sizeof(csOutMessage), m_szMessageText, m_szAppName, szDumpPath);
//PrintError(_T("%s"), csOutMessage);
::MessageBoxW(NULL, csOutMessage, m_szAppName, MB_OK);
}
else
{
swprintf(szScratch, sizeof(szScratch), L"Failed to create dump file '%s' (error %d)", szDumpPath, GetLastError());
szResult = szScratch;
}
}
}
else
{
szResult = L"DBGHELP.DLL too old";
}
}
else
{
szResult = L"DBGHELP.DLL not found";
}
if (szResult)
{
//PrintDebug(_T("[CrashDump] Mini Dump result:[%s]"),szResult);
}
return retval;
}
#endif

Create StartMenu Entry

i try to create link to file in StartMenu folder, my code:
bool createStartMenuEntry(string targetPath, string name){
std::wstring stemp = s2ws(targetPath);
LPCWSTR target = stemp.c_str();
WCHAR startMenuPath[MAX_PATH];
HRESULT result = SHGetFolderPathW(NULL, CSIDL_COMMON_PROGRAMS, NULL, 0, startMenuPath);
if (SUCCEEDED(result)) {
std::wstring linkPath = std::wstring(startMenuPath) + s2ws(name);
LPCWSTR link = linkPath.c_str();
//TEST MESSAGE!!!
MessageBox(NULL, LPCSTR(target), LPCSTR(link), MB_ICONWARNING);
CoInitialize(NULL);
IShellLinkW* shellLink = NULL;
result = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_ALL, IID_IShellLinkW, (void**)&shellLink);
if (SUCCEEDED(result)) {
shellLink->SetPath(target);
//shellLink->SetDescription(L"Shortcut Description");
shellLink->SetIconLocation(target, 0);
IPersistFile* persistFile;
result = shellLink->QueryInterface(IID_IPersistFile, (void**)&persistFile);
if (SUCCEEDED(result)) {
result = persistFile->Save(link, TRUE);
persistFile->Release();
}
else {
return false;
}
shellLink->Release();
}
else {
return false;
}
}
else {
return false;
}
return true;
}
String to widestring conversion:
std::wstring s2ws(const std::string& s)
{
int len;
int slength = (int)s.length() + 1;
len = MultiByteToWideChar(CP_ACP, 0, s.c_str(), slength, 0, 0);
wchar_t* buf = new wchar_t[len];
MultiByteToWideChar(CP_ACP, 0, s.c_str(), slength, buf, len);
std::wstring r(buf);
delete[] buf;
return r;
}
When I call my func like createStartMenuEntry("E:\\file.exe" , "File"), in test message I have only first letters of path and shortcut isn't created, I think, problem in unicode conversion.
There are multiple problems here:
MessageBox(NULL, LPCSTR(target), LPCSTR(link), MB_ICONWARNING); is all kinds of wrong. You should not be casting strings like this. If you are compiling without UNICODE defined, you must use MessageBoxW() to display a LPCWSTR string. You get a single character because "c:\\" as a Unicode string is 'c',0,':',0,'\\',0,0,0 in memory, and that is the same as a "c" string when treated as a narrow ANSI string.
You ignore the result of persistFile->Save()! You also ignore the results of SetPath() and SetIconLocation().
A normal user cannot write to CSIDL_COMMON_PROGRAMS, only administrators have write access to that folder, because it is shared by all users. If you are not planning to require UAC elevation, you must write to CSIDL_PROGRAMS instead.
You should not use std::string to store paths, only std::wstring and WCHAR*/LP[C]WSTR, because paths that contain certain Unicode characters cannot be represented in a narrow ANSI string.

CreateFileMapping for Directory

I have this function which gives the full file name(path) from the file handle. The only problem is CreateFileMapping fails for directory handles. Is there a workaround for it?
I get the handle using NtCreateFile()
ULONG status = NtCreatefile(&f, GENERIC_ALL, &oa, iosb, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_OPEN, FILE_OPEN_BY_FILE_ID , NULL, 0);
printf("status: %X, handle: %x\n", status, f);
AND
BOOL CHouseKeeper::GetFileNameFromHandle(HANDLE hFile)
{
BOOL bSuccess = FALSE;
TCHAR pszFilename[MAX_PATH+1];
HANDLE hFileMap;
// Get the file size.
DWORD dwFileSizeHi = 0;
DWORD dwFileSizeLo = GetFileSize(hFile, &dwFileSizeHi);
if( dwFileSizeLo == 0 && dwFileSizeHi == 0 )
{
_tprintf(TEXT("Cannot map a file with a length of zero.\n"));
return FALSE;
}
// Create a file mapping object.
//It fails here if a directory handle is passed, it returns 0
hFileMap = CreateFileMapping(hFile,
NULL,
PAGE_READONLY,
0,
1,
NULL);
if (hFileMap)
{
// Create a file mapping to get the file name.
void* pMem = MapViewOfFile(hFileMap, FILE_MAP_READ, 0, 0, 1);
if (pMem)
{
if (GetMappedFileName (GetCurrentProcess(),
pMem,
pszFilename,
MAX_PATH))
{
// Translate path with device name to drive letters.
TCHAR szTemp[BUFSIZE];
szTemp[0] = '\0';
if (GetLogicalDriveStrings(BUFSIZE-1, szTemp))
{
TCHAR szName[MAX_PATH];
TCHAR szDrive[3] = TEXT(" :");
BOOL bFound = FALSE;
TCHAR* p = szTemp;
do
{
// Copy the drive letter to the template string
*szDrive = *p;
// Look up each device name
if (QueryDosDevice(szDrive, szName, MAX_PATH))
{
size_t uNameLen = _tcslen(szName);
if (uNameLen < MAX_PATH)
{
bFound = _tcsnicmp(pszFilename, szName, uNameLen) == 0
&& *(pszFilename + uNameLen) == _T('\\');
if (bFound)
{
// Reconstruct pszFilename using szTempFile
// Replace device path with DOS path
TCHAR szTempFile[MAX_PATH];
StringCchPrintf(szTempFile,
MAX_PATH,
TEXT("%s%s"),
szDrive,
pszFilename+uNameLen);
StringCchCopyN(pszFilename, MAX_PATH+1, szTempFile, _tcslen(szTempFile));
}
}
}
// Go to the next NULL character.
while (*p++);
} while (!bFound && *p); // end of string
}
}
bSuccess = TRUE;
UnmapViewOfFile(pMem);
}
CloseHandle(hFileMap);
}else {
wcout<<GetLastError()<<endl;
}
_tprintf(TEXT("File name is %s\n"), pszFilename);
return(bSuccess);
}
You can use NtQueryInformationFile with FileNameInformation to retrieve the name associated with a file handle.