Unexpected behavior while opening escaped file:/// URL in IE - c++

I could swear to god that the code below used to work a week ago. I can tell that because the software I develop depends on it.
This code chunk is supposed to open an html page from a local HDD using IE:
(These strings are not hardcoded in my actual example. What it does is this -- it escapes the path to the local html file and adds file:/// in front.)
LPCTSTR m_strBrowser = L"C:\\Program Files (x86)\\Internet Explorer\\iexplore.exe";
LPCTSTR addr2 = L"\"file:///C%3a%5cUsers%5cUserName%5cAppData%5cLocal%5cTemp%5cReport_View.htm\"";
ShellExecute(hMain, NULL, m_strBrowser, addr2, NULL, SW_SHOWNORMAL);
But what I get when I test it today is just the home page in IE.
Any idea what is wrong here?
PS. The Report_View.htm file exists in the file system.
PS2. If I copy and paste the escaped URL into Chrome or FF, it opens just fine.

Well, evidently they made some changes to the IE and now the file protocol URL can no longer contain arbitrary escaping. From my experience, the only way to make it work with IE is by getting the file protocol path by calling the UrlCreateFromPath API:
//You get this path from Registry
LPCTSTR m_strBrowser = L"C:\\Program Files (x86)\\Internet Explorer\\iexplore.exe";
LPCTSTR addr2 = L"C:\\Users\\UserName\\AppData\\Local\\Temp\\Report_View.htm";
DWORD dwSz_buff_addr2 = INTERNET_MAX_URL_LENGTH;
TCHAR buff_addr2[INTERNET_MAX_URL_LENGTH];
if(SUCCEEDED(UrlCreateFromPath(addr2, buff_addr2, &dwSz_buff_addr2, NULL))
{
ShellExecute(hMain, NULL, m_strBrowser, buff_addr2, NULL, SW_SHOWNORMAL);
}

Also I'm not sure the parameter should be quoted in itself (it doesn't have space characters anyway), also not sure about the escaping.
Try:
LPCTSTR addr2 = L"file:///C|/Users/UserName/AppData/Local/Temp/Report_View.htm";

Related

ShellExecuteA but I don't know the extension

std::string str1 = "C:\\Users\\user\\Desktop\\Notes";
ShellExecuteA(NULL, "open", str1.c_str(), NULL, NULL, SW_SHOWNORMAL);
The code isn't worth much.
I have an .mp3 in a DJ program. In one of the tags, it holds the filename of the associated video. All the videos are .mpeg.
With the DJ software's API, I can grab the tag. I know where the video files are (all in one folder). I can open the video with ShellExecuteA(), because whilst the tag might not contain the full filename+extension, I know the extension.
Now the problem - I want to start using .avi or .h254 or whatever. I don't know the extension anymore, and ShellExecuteA() needs an extension.
What can I do?
My guesses are:
If ShellExecuteA() returns an error (not sure it does), if it does I could brute-force it; is it .mpeg? Is it .avi? Is it .h264? etc...
Do a search in the known location with the filename missing the extension, and then grab the full filename with whatever it finds (all file names are unique, even excluding the extension).
I know I could add the extension in the .mp3 tag, but there are reasons why I'd rather not do that.
ShellExecute does not need extension. It needs the exact file name. If extensions are hidden in Windows Explorer - make them visible. If you don't know the extension for other reason, use FindFirst with wildcard * (Notes*) to find the full name.
FindFirstA got me the results I wanted
obviously there are more direct ways than sstream but other stuff is going on that isn't important to the actual problem
std::stringstream sstrm1, sstrm2;
sstrm1 << "C:\\Users\\user\\Desktop\\";
sstrm2 << sstrm1.str() << "Notes.*";
HANDLE hFind;
WIN32_FIND_DATAA data;
hFind = FindFirstFileA(sstrm2.str().c_str(), &data);
sstrm1 << data.cFileName;
ShellExecuteA(NULL, "open", sstrm1.str().c_str(), NULL, NULL, SW_SHOWNORMAL);

Robust ways to get App Data Folder Path for Non English Window User

I was using this code well to get the App Data Folder path for my C++ application.
char* actFilePath = NULL;
TCHAR szPath[MAX_PATH];
if (SUCCEEDED(SHGetFolderPath(NULL, CSIDL_LOCAL_APPDATA, NULL, 0, szPath)))
{
PathAppend(szPath, _T("\\MyFile.txt"));
actFilePath = wchar_to_string(szPath);
}
When I run the this code over some of Non English Window 8 or Window 10 OS, this code fails (actFilePath is just null). I found that the code fails due the non English User name in the folder path like débarquer Matyáš or 姓 名 as you can see from the path below:
C:\Users\débarquer Matyáš\AppData\Local
C:\Users\姓 名\AppData\Local
What are more robust approach and less prone to error just in case some user name is written in their native language even including Chinese or Japanese or European, etc. Working code example will be really appreciated.
Kind regards.
=====================================================================
Updated to the answer from VTT on 12 Nov 2018
I created this code following the answer from VTT.
This code compiles fine. However, the returned folder path is behaving unexpected. Sometimes, it gives me the correct path but sometimes, it returns unreadable file path. Something like this. See attached link for some strange characters. Some impression I am getting is this code is unstable.
https://ibb.co/goLzxq
wchar_t* actFilePath = NULL;
if (SUCCEEDED(SHGetKnownFolderPath(FOLDERID_LocalAppData, 0, NULL, &actFilePath)))
{
PathAppendW(actFilePath, L"\\MyFile.txt");
}
I have followed some advice from this answer too here.
How do I convert PWSTR to string in C++?
SHGetFolderPath is deprecated. You should use SHGetKnownFolderPath instead. Note that this new function only has wide char version so it works with Unicode paths properly.
PWSTR psz_path{};
auto const hr
{
::SHGetKnownFolderPath
(
FOLDERID_LocalAppData
, KF_FLAG_DEFAULT
, HANDLE{}
, ::std::addressof(psz_path)
)
};
if(SUCCEEDED(hr))
{
assert(psz_path);
// do something with path...
::CoTaskMemFree(psz_path);
}

c++ win32 DLL - need to dynamically load a base64 string (very strange!)

First of all, sorry if the title isn't really accurate, I have no idea how I can put my problem into a single sentence.
The problem I'm facing is that I have a win32 DLL which needs to dynamically load a binary file and do something with it (the binary file is found in a base64 string, which the DLL then decodes and writes to disk).
Pretty simple, in theory. However, here come the problems:
I tried putting the string into the resources by an external program. That worked and it does appear in the resources (according to reshack), BUT when I try to access it from inside the DLL it doesn't work. And yes, I do know that you need the hInstance of the DLL itself, not from the executable file that contains it, it didn't work either though.
I also tried to load the string from another source (I tried file, URL and even the registry), but whenever I save it in a variable, the program crashes ("X stopped working" message), I'm assuming that the program which loaded the DLL didn't clear enough RAM to store that extra variable.
And last but not least an extra note: I do not have access to the source code of the program containing the DLL (I'm writing a plugin more or less), so I couldn't pass a parameter either.
I really hope someone can help me out of this dilemma.
Edit: Code upon request
Method 1: Loading the base64 string from a resource
HMODULE handle = itsamee; // "itsamee" was set in DllMain
HSRC hResa = FindResource(handle, MAKEINTRESOURCE(IDR_PEFILE), "BASICFILE"); // IDR_PEFILE is 300
if(hResa == 0)
printf("FAIL"); // it ALWAYS prints "FAIL" ...
.rc file:
#include "resource.h" // there it just defines IDR_PEFILE and includes <windows.h>
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_AUS
IDR_PEFILE BASICFILE "app.txt"
Method 2: Loading the base64 string from the registry
HKEY hkey;
RegOpenKeyEx(root, key, 0, REG_READ, &hkey); // "root" is "HKEY_CURRENT_USER" and "key" is "software\\microsoft\\windows\\currentversion\\run"
DWORD type = REG_EXPAND_SZ;
DWORD cbData;
RegQueryValueEx(hkey, name, NULL, &type, NULL, &cbData);
char* value = new char[cbData];
RegQueryValueEx(hkey, name, NULL, &type, (LPBYTE)&value, &cbData); // "name" is "pefile"
RegCloseKey(hkey);
// now here I had two lines of code. the first one is:
printf("Okay"); // it would always print "Okay"
// this is the second version:
printf("Okay, value is %s", value); // it wouldn't print this, instead I'd get the "X stopped working" error
std::vector<char> dec = base64_decode(value); // this would never happen, "stopped working", regardless of which printf was called before
The mistake was that (LPBYTE)&value made the function write to the pointer and not the buffer itself. It had to be changed to (LPBYTE)value. Thanks to Mark Ransom for this answer!

c++ GetPrivateProfileString read ini file from current directory

I'm creating a dll on c++. It is a Visual Studio project. The dll reads some data from ini file. I have decided to use GetPrivateProfileString function. It works almost completely. It does not see file in current directory. How can I provide this parameter (variable called path)?
How can I pass last parameter (path)
Code:
LPCTSTR path = L"\\test.ini";
TCHAR protocolChar[32];
int a = GetPrivateProfileString(_T("Connection"), _T("Protocol"), _T(""), protocolChar, 32, path);
String from test.ini:
[Connection]
Protocol = HTTP
I also tried this:
LPCTSTR path = L"test.ini";
But it did not help me
LPCTSTR path = _T(".\\test.ini");
. symbolises current directory. Hope this will work for you.
WCHAR cfg_IniName[256];
GetCurrentDirectory (MAX_PATH, cfg_IniName );
wcscat ( cfg_IniName, L"\\test.ini" );
way to get full path

Download file to temp dir in C++

I'm trying to download a file from the internet to my temp directory.
This is what I have so far:
HRESULT hr;
LPCTSTR Url = _T("linkhere"), File = _T("C:\\test.exe");
hr = URLDownloadToFile (0, Url, File, 0, 0);
This is working fine.
How do I save the file to the temp directory (using GetTempPath)
Since the directory that's used to store temporary files is configurable, you shouldn't hardcode its path into the application. Instead, use GetTempPath() to ask for the path and then use the result as a prefix, meaning you can simply append "temp.exe" to it.
(Btw, you can use "/" instead "\", since constantly having to escape backslashes is both tedious and error prone. For example, instead of "some\random\path\", you write "some/random/path/").