I'm having a hard time converting a string into LPWSTR
so I can use the PathStripToRoot()
function.
Well for one the MSDN documation says I need LPTSTR
variable (http://msdn.microsoft.com/en-us/library/windows/desktop/bb773757(v=vs.85).aspx), but Visual Studio 2013 says I need LPWSTR
.
Here is a code snippet of my function:
fileStat fileCreate(const string& targetFile)
{
fileStat filez;
fstream file(targetFile.c_str());
if (!file)
{
cout << "File does not exist" << endl;
}
std::ifstream in(targetFile, ios::binary | ios::ate);
int a = in.tellg();
cout << "File size(bytes): " << in.tellg() << endl << endl;
file.close();
wstring stemp = strChange(targetFile);
LPCWSTR result = stemp.c_str();
/* Tried the below code but that did not work
LPWSTR ws = new wchar_t[targetFile.size() + 1];
copy(targetFile.begin(), targetFile.end(), ws);
ws[targetFile.size()] = 0;
*/
cout<<"\n\n"<<PathStripToRoot(ws)<<"\n\n";
...
filez.fileSize = a;
return filez;
}
A lot of people have said to use MultiByteToWideChar()
function but I looked at the MSDN documation and have no idea how it works. Is there an easier way than using MultiByteToWideChar()
?
You may want to use Unicode UTF-16 strings in modern Windows applications when dealing with Win32 APIs: the std::wstring
class (based on wchar_t
) is OK for that with Visual C++.
Then, you can wrap the Win32 C API PathStripToRoot()
in some C++ code, using convenient string classes instead of raw C-like string buffers.
Consider the following commented code as an example:
// Set Unicode mode
#define UNICODE
#define _UNICODE
// Windows SDK Headers
#include <Windows.h> // Win32 Platform SDK
#include <Shlwapi.h> // For PathStripToRoot()
#include <Strsafe.h> // For StringCchCopy()
// Standard C++ Headers
#include <exception> // For std::exception
#include <iostream> // For console output
#include <stdexcept> // For std::invalid_argument, std::runtime_error
#include <string> // For std::wstring
// For using PathStripToRoot()
#pragma comment(lib, "Shlwapi.lib")
// C++ wrapper around PathStripToRoot() Win32 API
std::wstring RootFromPath(const std::wstring& path)
{
// Buffer for PathStripToRoot()
wchar_t pathBuffer[MAX_PATH];
// Copy the input string into the buffer.
// Beware of buffer overruns!
HRESULT hr = ::StringCchCopy(pathBuffer, // dest
_countof(pathBuffer), // dest size
path.c_str()); // source
if (hr == STRSAFE_E_INSUFFICIENT_BUFFER)
{
// Copy failed due to insufficient buffer space.
// May accept this case or throw an exception
// based on the context...
// In this case, I just throw here.
throw std::invalid_argument("RootFromPath() - Path string too long.");
}
if (hr != S_OK)
{
throw std::runtime_error("RootFromPath() - StringCchCopy failed.");
}
// Call the Win32 C API using the raw C buffer
if (! ::PathStripToRoot(pathBuffer))
{
// No valid drive letter was found.
// Return an empty string
return std::wstring();
}
// Return a std::wstring with the buffer content
return std::wstring(pathBuffer);
}
// Test
int main()
{
try
{
const std::wstring path = L"C:\\Path1\\Path2";
const std::wstring root = RootFromPath(path);
std::wcout << "The content of the path before is:\t" << path << std::endl;
std::wcout << "RootFromPath() returned: \t" << root << std::endl;
}
catch(const std::exception& ex)
{
std::cerr << "\n*** ERROR: " << ex.what() << std::endl;
}
}
Compiled from command line:
C:\Temp\CppTests>cl /EHsc /W4 /nologo TestPathStripToRoot.cpp
Output:
C:\Temp\CppTests>TestPathStripToRoot.exe The content of the path before is: C:\Path1\Path2 RootFromPath() returned: C:\
On that particular point of your question:
Well for one the MSDN documation says I need
LPTSTR
variable, but Visual Studios says I needLPWSTR
.
LPTSTR
is a typedef equivalent to TCHAR*
.LPWSTR
is a typedef equivalent to WCHAR*
, i.e. wchar_t*
.
TCHAR
is a placeholder for a character type, that can be expanded to char
or wchar_t
, depending if you are in ANSI/MBCS or Unicode build mode.
Since VS2005, Visual Studio has been using Unicode builds as default.
So, unless you are maintaining an old legacy app that must use ANSI/MBCS, just use Unicode in modern Win32 applications. In this case, you can directly use wchar_t
-based strings with Win32 APIs, without bothering with the old obsolete TCHAR-model.
Note that you can still have std::string
s (which are char
-based) in your code, e.g. to represent Unicode UTF-8 text. And you can convert between UTF-8 (char
/std::string
) and UTF-16 (wchar_t
/std::wstring
) at the Win32 API boundaries.
For that purpose, you can use some convenient RAII wrappers to raw Win32 MultiByteToWideChar()
and WideCharToMultiByte()
APIs.
The right way to think about building a Windows application is to pretend that 8-bit strings do not exist. Otherwise, the encoding of your string will vary based on the user's language settings, and your app will not be able "global ready" because there will always be some characters not representable by the user's current settings. 8-bit strings in Win32 are legacy from the 1990s and a good Win32 app uses PWSTR
everywhere. Notice for instance that on Windows CE or WinRT the "A functions" don't even exist, that should give you some hint about how Microsoft feels about the issue.
Now, in practical terms, you may be interacting with non-Windows specific code that uses 8-bit strings. IMO the best approach to use for that is to say by convention that all such strings are UTF-8, and use MultiByteToWideChar
and WideCharToMultiByte
to convert to and from PWSTR
. Be sure to use CP_UTF8
. But for Windows specific code, please do define the UNICODE
and _UNICODE
macros, forget that TCHAR
, TSTR
, *A
functions and other such accidents of history exist and use PWSTR
and WCHAR
everywhere. Your code will be saner for it.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With