How get the unicode string as argument to visual C++ MFC project? - c++

I have a Visual C++ MFC project which will open the PDF File. I need to lauch this Project EXE from Python code with file path as argument. The File path is an Unicode string e.g. u'C:\\Desktop\\Rahul\xadShikhare.pdf' ("\xad" is SOFT_HYPHEN unichar number 173, Actual file path is C:\Desktop\Rahul-Shikahre.pdf).
I want to pass this unicode string to OpenDocumentFil(LPCTSTR file_path) function of CWin class which will open the file.
How to read an unicode string (string have SHOF_HYPHE unichar) from command line in Visual C++ and store it into LPCTSTR variable?
I tried with following code but it showing error as Path not exist.
LPWSTR cmd_arg = GetCommandLineW();
//---This is for removing Application exe name from cmd_arg
wstring all_args = cmd_arg;
int position = all_args.find(L" ");
wstring file_path = L"";
if (position > 0)
{
file_path = all_args.substr(position + 1);
file_path.append(L"");
MessageBox(NULL, file_path.c_str(), L"", MB_OK);
}
//--------------
if (file_path != L"")
{
OpenDocumentFile(file_path.c_str());
}
The above code is giving the problem only if the arguments have SOFT-HYPHE as unicode char in cmd_arg string.

Related

VS 2019 C++ console app gets parameters in UTF-8 instead of expected UTF-16LE

I'm building a new project in Visual Studio 2019. It's a console app that includes MFC headers. Here's the relevant code:
int main(int argc, TCHAR* argv[]) // VS wrote "int main()", I added parameters myself.
{
int nRetCode = 0;
HMODULE hModule = ::GetModuleHandle(nullptr);
if (hModule != nullptr)
{
// initialize MFC and print and error on failure
if (!AfxWinInit(hModule, nullptr, ::GetCommandLine(), 0))
{
// TODO: code your application's behavior here.
wprintf(L"Fatal Error: MFC initialization failed\n");
nRetCode = 1;
}
else
{
nRetCode = MyFunction(argc, argv);
}
}
else
{
// TODO: change error code to suit your needs
wprintf(L"Fatal Error: GetModuleHandle failed\n");
nRetCode = 1;
}
return nRetCode;
}
Most of this is boilerplate code generates by VS. I added parameters to the main function and the call to my own code, namely MyFunction(). It built just fine; didn't issue so much as a warning. On the very first test run I found that the text in argv[1] and argv[2] are in plain 8-bit ASCII or UTF-8. I was expecting UNICODE as UTF-16LE.I do have the project properties set to use UNICODE. What have I done wrong to get command line parameters in UTF-8? Here's my setup in VS 2019:
My OS is Windows 10.
main() only works with char in the argv[] array. If you want to use wchar_t instead, you need to rename main() to wmain() instead.
Or, since you are using TCHAR, you can rename main() to _tmain(), so that it will automatically map to main() in a MBCS build, and to wmain() in a Unicode build. See What is difference between main and _tmain in Visual studio

Why does my file/dir manipulation works fine on Windows but not on Linux?

I am trying to create a file for handling session with in a directory name "IPM" i.e my project's name.
I access this file every time a user logged in and logged out plus I also access it at some more places thus i have created this function to create a path string so as to where the file is created on different OS
std::string SessionManager::createPathString(std::string sFileName)
{
char* pPath = getenv(HOME);
std::string sUserName(pPath);
createDirectory(sUserName);
std::replace(sUserName.begin(), sUserName.end(), '\\', '/');
sUserName.append("/IPM");
sUserName.append("/");
sUserName.append(sFileName);
return sUserName;
}
I call this function to get me the file path and the function to create directory goes like this
int createDirectory(std::string sUserName)
{
sUserName += "\\IPM";
#ifdef _WIN32
int ret = _mkdir(sUserName.c_str());
#elif __linux__
int ret = mkdir(sUserName.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
#endif
return ret;
}
It creates a directory on windows but fails on Linux, in case the directory or file is not present it gets created on windows, but not on Linux.
Is there any way to do it by boost, since I am new to C++ this look typical.
Yes, there is Boost.Filesystem library, that has create_directory function. You'd better use that, because it can handle different separators (like / vs \) more properly than just replacing chars in a strings from time to time.
To store path, you should then use boost::filesystem::path objects, that can created from char*, std::string or std::wstring strings, then append using operator /=, then call create_directory or any other method you need:
using namespace boost::filesystem;
path p(userName);
p /= "IPM"; // By the way, you should make this constant, don't you?
p /= sFileName;
if (!create_directory(p)) {
cerr << "Failed to create directory";
}
More complete tutorial for Boost.Filesystem is available here.

How can I open a file inside of an exe inside of my c++ app

Question is I have this button that when clicked I would like it open a file for me inside of a specific executable.
I am a tad rusty on c++ and this is a legacy application using c++ 6.0
built on windows xp.....So any help would be greatly appreciated!
Here is my code cpp
void CJunkView::OnCadkeyButton()
{
CString fileToOpen = "C:\\Documents and Settings\\Administrator\\Desktop\\x.prt";
CString exePath = "C:\\CK19\\Ckwin.exe";
system ("start (exePath), (fileToOpen)");
}
When I click this button it returns this Windows cannot find 'exePath,'.Make sure you typed the name correctly and then try again.
You need to build a string that contains the entire system call and the pass the buffer of that string to system()
Edit:
In response to the comment by IInspectable we could just use the implicit conversion operator operator LPCTSTR()
void CJunkView::OnCadkeyButton()
{
CString fileToOpen = "C:\\Documents and settings\\Administrator\\Desktop\\x.prt";
CString exePath = "C:\\CK19\\Ckwin.exe";
CString cmd = "start " + exePath + ", " + fileToOpen;
system (cmd);
}

fopen_s(&fp,"FileName.txt",w+); not working when I give relative path of the file & works only when absolute path is given

I find that the API,
_tfsopen()
is not working when I just give the relative file path (JUST FILE NAME) in
fopen_s(&fp,"FileName.txt",w+);
But if I give the absolute path of the txt file then it's working fine. So the problem is in getting the current working directory (CWD). How do I get the CWD and make this API work?
This API definition is present in:
C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\crt\src\fopen.c
This is what fopen.c has:
errno_t __cdecl _tfopen_s (
FILE ** pfile,
const _TSCHAR *file,
const _TSCHAR *mode
)
{
_VALIDATE_RETURN_ERRCODE((pfile != NULL), EINVAL);
*pfile = _tfsopen(file, mode, _SH_SECURE); // ERROR IS OCCURING AT THIS LINE. IT's NOT ABLE TO OPEN THE FILE.
if(*pfile != NULL)
return 0;
return errno;
}
This code let you get current working directory:
#include <direct.h>
char cwd[MAX_PATH_SIZE];
_getcwd(cwd, MAX_PATH_SIZE);

Get path to My Documents

From Visual C++, how do I get the path to the current user's My Documents folder?
Edit:
I have this:
TCHAR my_documents[MAX_PATH];
HRESULT result = SHGetFolderPath(NULL, CSIDL_MYDOCUMENTS, NULL, SHGFP_TYPE_CURRENT, my_documents);
However, result is coming back with a value of E_INVALIDARG. Any thoughts as to why this might be?
It depends on how old of a system you need compatibility with. For old systems, there's SHGetSpecialFolderPath. For somewhat newer systems, there's SHGetFolderPath. Starting with Vista, there's SHGetKnownFolderPath.
Here's some demo code that works, at least on my machine:
#include <windows.h>
#include <iostream>
#include <shlobj.h>
#pragma comment(lib, "shell32.lib")
int main() {
CHAR my_documents[MAX_PATH];
HRESULT result = SHGetFolderPath(NULL, CSIDL_PERSONAL, NULL, SHGFP_TYPE_CURRENT, my_documents);
if (result != S_OK)
std::cout << "Error: " << result << "\n";
else
std::cout << "Path: " << my_documents << "\n";
return 0;
}
Use the SHGetFolderPath Windows API function and request CSIDL_MYDOCUMENTS.
Using Visual Studio 2017 with an MFC application under Windows 10 I am using the following code snippet with SHGetKnownFolderPath function to get the current user's Documents folder:
#include <string> // include file for C++ native strings
// . . . other code.
PWSTR ppszPath; // variable to receive the path memory block pointer.
HRESULT hr = SHGetKnownFolderPath(FOLDERID_Documents, 0, NULL, &ppszPath);
std::wstring myPath;
if (SUCCEEDED(hr)) {
myPath = ppszPath; // make a local copy of the path
}
CoTaskMemFree(ppszPath); // free up the path memory block
Note that the documentation has this to say about the path variable usage and the path returned:
ppszPath [out]
Type: PWSTR*
When this method returns, contains the address of a pointer to a
null-terminated Unicode string that specifies the path of the known
folder. The calling process is responsible for freeing this resource
once it is no longer needed by calling CoTaskMemFree. The returned
path does not include a trailing backslash. For example, "C:\Users" is
returned rather than "C:\Users\".
For a list of the FOLDERID_ arguments possible see the MSDN article KNOWN_FOLDER_FLAG enumeration.
Note that CSIDL_PERSONAL will not return the desired folder if the user has changed the default save folder in the Win7 Documents library. To get the right folder, you need to use SHLoadLibraryFromKnownFolder to obtain the IShellLibrary for the Documents library, use IShellLibrary::GetDefaultSaveFolder to get the IShellItem for the library's default save folder, and finally use IShellItem::GetDisplayName to get the folder name.
std::string GetMyDocumentsFolderPath()
{
wchar_t Folder[1024];
HRESULT hr = SHGetFolderPathW(0, CSIDL_MYDOCUMENTS, 0, 0, Folder);
if (SUCCEEDED(hr))
{
char str[1024];
wcstombs(str, Folder, 1023);
return str;
}
else return "";
}
cout<<GetMyDocumentsFolderPath()<<endl;
how about this solution? Its working fine for me.