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 need LPWSTR
.
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.