LPCWSTR to string conversion issue in code c++ VS 2010 - c++

I am trying to find files with specific name and deleting them in c++ as this code works fine if i give direct desktop path to it L"path//" but as path of desktop is different due to different user and system so i what i am doing at the top is to get desktop path in string variable and assigning it rather than direct path.
string desk=getenv("DESKTOP");
WIN32_FIND_DATAW fd;
HANDLE hFind = FindFirstFileW(desk, &fd);
if (hFind != INVALID_HANDLE_VALUE)
{
do
{
DeleteFileW((wstring(desk) + fd.cFileName).c_str());
} while (FindNextFileW(hFind, &fd));
FindClose(hFind);
}
I am getting the following error
Error 4 error C2664: 'FindFirstFileW' : cannot convert parameter 1
from 'std::string' to 'LPCWSTR'
I have already tried using wstring and wchar but it gives error again. Can anyone please help me to sortout this issue. looking for correction in code

Windows will usually have two versions of a function, an A suffix will generally be it accepts chars, a W suffix accepts a wchar_t, and without the suffix usually ends up as a macro for whatever character set is selected. Generally the string types they will accept is LPCWSTR (long pointer to wide constant string) or LPCSTR (long pointer to constant string).
First argument of FindFirstFileW() takes a LPCWSTR.
LPCWSTR is a typedef for const wchar_t*. You are passing an std::string, so it's the wrong type.
Just be consistent with the string type, either do:
wstring desk = _wgetenv(L"DESKTOP");
string findDigitsInBinary(int A) {
WIN32_FIND_DATAW fd;
HANDLE hFind = FindFirstFileW(desk.c_str(), &fd); // First argument takes LPCWSTR
or:
string desk = getenv("DESKTOP");
string findDigitsInBinary(int A) {
WIN32_FIND_DATAA fd;
HANDLE hFind = FindFirstFileA(desk.c_str(), &fd); // First arg takes LPCSTR
Notice that in neither case you are passing the string class, but the character buffer held by the string.
The suffixes W and A I think stand for wide and ANSI.

Since you're calling Win32 functions directly, consistency suggests using GetEnvironmentVariableW instead of getenv. The reliance on a DESKTOP variable is already very Windows-specific; this isn't portable code by any means.

Related

How to concatenate a LPCWSTR?

How would I take...
string modelPath = "blah/blah.obj"
and concatenate it with...
L" not found."
While passing it in as LPCWSTR. I tried to do
(LPCWSTR)(modelPath + " was not found.").c_str()
However that did not work. Here is a larger example of what it looks like now.
if(!fin)
{
MessageBox(0, L"Models/WheelFinal.txt not found.", 0, 0); //
return;
}
LPCWSTR is a L ong P ointer to a C onstant W ide STR ing. Wide strings, at least in Win32, are 16 bits, whereas (const) char strings (i.e. (C)STR or their pointer-counterparts LP(C)STR) are 8 bits.
Think of them on Win32 as typedef const char* LPCSTR and typedef const wchar_t* LPCWSTR.
std::string is an 8-bit string (using the underlying type char by default) whereas std::wstring is a wider character string (i.e. 16-bits on win32, using wchar_t by default).
If you can, use std::wstring to concatenate a L"string" as a drop-in replacement.
A note on MessageBox()
Windows has a funny habit of defining macros for API calls that switch out underlying calls given the program's multibyte configuration. For almost every API call that uses strings, there is a FunctionA and FunctionW call that takes an LPCSTR or LPWCSTR respectively.
MessageBox is one of them. In Visual Studio, you can go into project settings and change your Multi-Byte (wide/narrow) setting or you can simply call MessageBoxA/W directly in order to pass in different encodings of strings.
For example:
LPWCSTR wideString = L"Hello, ";
MessageBoxW(NULL, (std::wstring(wideString) + L"world!").c_str(), L"Hello!", MB_OK);
LPCSTR narrowString = "Hello, ";
MessageBoxA(NULL, (std::string(narrowString) + "world!").c_str(), "Hello!", MB_OK);
If you can change modelPath to std::wstring, it becomes easy:
MessageBox(nullptr, (modelPath + L" not found.").c_str(), nullptr, 0);
I changed your 0 pointer values into nullptr as well.
Since std::string represents a narrow string, std::wstring represents a wide string, and the two are wildly different, casting from one representation to the other does not work, while starting with the appropriate one does. On the other hand, one can properly convert between representations using the new <codecvt> header in C++11.

How do I call the UrlCanonicalize API function correctly?

HRESULT UrlCanonicalize(
_In_ PCTSTR pszUrl,
_Out_ PTSTR pszCanonicalized,
_Inout_ DWORD *pcchCanonicalized,
DWORD dwFlags
);
Example:
LPCTSTR pszURL = URL.c_str();
LPSTR pszOutPut = new CHAR[ strUrl.length ];
DWORD* dwCount = new DWORD[ strUrl.length ];
hRes = UrlCanonicalize( pszURL, pszOutPut,dwCount, URL_ESCAPE_UNSAFE );
Output:
E_INVALIDARG
This API fails and returns E_INVALIDARG every time I try to call it. Please give me a working code snippet to call the UrlCanonicalize function.
If you know the C++ language, the SDK documentation for the function pretty much tells you everything that you need to know:
You pass it a C-style nul-terminated string that contains your URL.
You pass it pointer to a buffer to receive the output string.
You pass it one or more flags that customize the function's behavior.
And finally, it returns to you an HRESULT value, which is an error code. If it succeeds, that value will be S_OK. If it fails, it will be some other error code.
It works like this:
std::wstring originalURL(L"http://www.example.com/hello/cruel/../world/");
// Allocate a buffer of the appropriate length.
// It needs to be at least as long as the input string.
std::wstring canonicalURL(originalURL.length() + 1, L'\0');
DWORD length = originalURL.length() + 1;
// Call the function to modify the string.
HRESULT hr = UrlCanonicalize(originalURL.c_str(), // input string
&canonicalURL[0], // buffer
&length, // pointer to a DWORD that contains the length of the buffer
URL_UNESCAPE | URL_ESCAPE_UNSAFE);
if (SUCCEEDED(hr))
{
// The function succeeded.
// Your canonicalized URL is in the canonicalURL string.
MessageBox(nullptr, canonicalURL.c_str(), L"The URL is:", MB_OK);
}
else
{
// The function failed.
// The hr variable contains the error code.
throw std::runtime_error("The UrlCanonicalize function failed.");
}
If you want to make sure that the buffer is sufficiently long (and avoid having to handle that error), use the constant INTERNET_MAX_URL_LENGTH (declared in WinInet.h) when allocating it:
std::wstring canonicalURL(INTERNET_MAX_URL_LENGTH, L'\0');
DWORD length = INTERNET_MAX_URL_LENGTH;
The code you tried has a couple of problems:
You've incorrectly initialized the dwCount variable. The function wants a pointer, but that doesn't mean you should declare the variable as a pointer. Nor do you want an array; this is a single DWORD value. So you need to declare it as a regular DWORD, and then use the address-of operator (&) to pass the function a pointer to that variable. Right now, you're passing the function garbage, so it's failing.
You're using C-style strings, which you should avoid in C++ code. Use the C++ string class (std::wstring for Windows code), which is exception safe and manages memory for you. As you already know, the c_str() member function gives you easy access to a C-style nul-terminated string like all C APIs want. This works fine, you do not need to use raw character arrays yourself. Avoid new whenever possible.
Potentially, a third problem is that you're trying to use the C++ string type std::string instead of std::wstring. The former is an 8-bit string type and doesn't support Unicode in a Windows environment. You want std::wstring, which is a wide string with Unicode support. It's what all the Windows API functions expect if you have the UNICODE symbol defined for your project (which it is by default).
Here you go:
LPCTSTR pszURL = URL.c_str();
DWORD nOutputLength = strUrl.length * 2 + 32;
LPTSTR pszOutPut = new TCHAR[nOutputLength];
hRes = UrlCanonicalize( pszURL, pszOutPut, &nOutputLength, URL_ESCAPE_UNSAFE);
On the third parameter you provided garbage instead of pointer to initialized value, so you had API failure back. MSDN has it all for you:
A pointer to a value that, on entry, is set to the number of characters in the pszCanonicalized buffer.

Concatenate two WCHAR_T arrays in C++

Dealing with these insane strings and arrays is giving me a headache...
Here's my code so far
wchar_t mypath[MAX_PATH];
wchar_t temppath[MAX_PATH];
GetModuleFileName(0, mypath, MAX_PATH);
GetTempPath(MAX_PATH, temppath);
CreateDirectory(???, NULL);
The first two windows API functions use the LPWSTR variable. The third uses LPCWSTR. What's the major difference? After I get the path for the TEMP directory, I want to create a new directory inside it called "test". This means I need to append (L"test") to my "temppath" variable. Can someone give me some tips on how to use these arrays. This is what makes C++ a pain. Why couldn't everyone just settle on one data type for strings. How is wchar_t even useful? It's so hard to use and manipulate.
Thanks guys!
The first two windows API functions use the LPWSTR variable. The third uses LPCWSTR. What's the major difference?
LPCWSTR is a const version of LPWSTR:
From LPCWSTR:
typedef const wchar_t* LPCWSTR;
From LPWSTR:
typedef wchar_t* LPWSTR, *PWSTR;
I want to create a new directory inside it called "test". This means I need to append (L"test") to my "temppath" variable.
Use a std::wostringstream:
std::wostringstream wos;
wos << temppath << L"\\test";
std::wstring fullpath(wos.str());
or just a std::wstring (as suggested by chris in the comments):
std::wstring fullpath(std::wstring(temppath) + L"\\test");
to produce a concatenated version. Then use c_str() as the argument to CreateDirectory():
if (CreateDirectory(fullpath.c_str(), NULL) ||
ERROR_ALREADY_EXISTS == GetLastError())
{
// Directory created or already existed.
}
else
{
// Failed to create directory.
}
Use PathCombine(), eg:
wchar_t temppath[MAX_PATH+1] = {0};
GetTempPath(MAX_PATH, temppath);
wchar_t mypath[MAX_PATH+8] = {0};
PathCombineW(mypath, temppath, L"test");
CreateDirectoryW(mypath, NULL);

LoadLibrary taking a LPCTSTR

I want to develop a plugin system using LoadLibrary.
My problem is: I want my function to take a const char* and LoadLibrary takes a LPCTSTR.
I had the bright idea to do (LPCSTR)path which kept giving me a module not found error.
Current code is below. If I uncomment the widepath = L.. line it works fine. I've read solutions using MFC but I'd like to not use MFC.
Current code:
bool PluginLoader::Load(char *path)
{
path = "Release\\ExamplePlugin.dll";
LPCTSTR widepath = (LPCTSTR)path;
//widepath = L"Release\\ExamplePlugin.dll";
HMODULE handle = LoadLibrary(widepath);
if (handle == 0)
{
printf("Path: %s\n",widepath );
printf("Error code: %d\n", GetLastError());
return false;
}
int (*load_callback)() = (int (*)()) GetProcAddress(handle, "_plugin_start#0");
if (load_callback == 0)
{
return false;
}
return load_callback() == LOAD_SUCCESS;
}
Use LoadLibraryA(), it takes a const char*.
Winapi functions that take strings exist in two versions, an A version that takes an Ansi string and a W version that takes a wide string. There's a macro for the function name, like LoadLibrary, that expands to either the A or the W flavor, depending if UNICODE is #defined. You are compiling your program with that #define in effect, so you get LoadLibraryW(). Simply cheat and use LoadLibraryA() explicitly.
I suggest you using TCHAR and LoadLibrary instead of using manually char or wchar_t and LoadLibraryA or LoadLibraryW to make a generic application, both for UNICODE and ASCII characters.
So you could do:
TCHAR x[100] = TEXT("some text");
I suggest you reading this article. LPCTSTR is a const TCHAR*.
Why use LoadLibrary instead of LoadLibraryW or LoadLibraryA? To support both UNICODE and ASCII without creating two different programs, one to work with char and the other with wchar_t.
Also, take a look at what Microsoft says about it: Conventions for Function Prototypes
If you continue to use a char * for the parameter, you'll run into cases where an unusual character is used in the filename and the LoadLibrary will fail. Change the function to use wchar_t instead, and while you're at it make the parameter const since you're not modifying the string.
bool PluginLoader::Load(const wchar_t *path)
I think you'll find that LPCTSTR on 32-bit Windows is a macro that expands to const wchar_t * when the program options are set to Unicode.
The approved method with LoadLibrary is to not use a char const *, but instead use a TCHAR const *, and use the _T macro on all literals:
bool PluginLoader::Load(TCHAR const *path) {
path = _T("Release\\ExamplePlugin.dll");
HMODULE handle = LoadLibrary(path);
if (handle == 0)
{
_tprintf(_T("Path: %s\n"),widepath );
_tprintf(_T("Error code: %d\n"), GetLastError());
return false;
}
int (*load_callback)() = (int (*)()) GetProcAddress(handle, _T("_plugin_start#0"));
if (load_callback == 0)
{
return false;
}
return load_callback() == LOAD_SUCCESS;
}
This will automatically use LoadLibraryW when _UNICODE/UNICODE are defined, and LoadLibraryA when they're not. Likewise, _T will give narrow or wide string literals on the same basis, so it all stays in sync.
I generally prefer to use the W suffixed functions explicitly, and use the L prefix on string literals. Windows works almost exclusively with wide strings internally anyway, so the version A-suffixed versions that take narrow string literals are mostly small stubs that convert their arguments to wide strings, then call the wide string version. Using the wide string version directly saves both time and memory.
Narrow string support in Windows was originally there primarily for compatibility with the long-since defunct Windows 95/98/SE/Me line that lacked wide string support. Those have been gone for quite a while, so about the only reason to use narrow literals now is because that's what you're being supplied from some outside source.

C++ std::string conversion problem on Windows

This is my procedure:
bool Open(std::string filename)
{
...
HANDLE hFile = CreateFile(filename.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
...
}
Error:'CreateFileW' : cannot convert parameter 1 from 'const char *' to 'LPCWSTR'
Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast
Where is the problem?
A std::string consists of an array of char's, and so the c_str function returns a const char*.
A LPCWSTR is a Long Pointer to a Constant Wide String, or in other words, const wchar_t*.
So you have a couple of options. Either get the filename as a wide string (std::wstring), or specify that you want the non-wide version of CreateFile instead. That can be done either by calling CreateFileA or disabling UNICODE in your project settings.
CreateFile is a macro which either resolves to CreateFileA (the char version) or CreateFileW (the wide char version) depending on whether or not unicode is enabled.
You have specified std::string, whose character type is char. And the code you're using CreateFile() in must be being compiled under the definition of the pre-processor symbol UNICODE, since that selects the actual underlying function CreateFileW().
Either get rid of the UNICODE definition, or explicitly use CreateFileA().
It looks like you are compiling with Unicode support turned on. You may want to turn it off, or if not use std::wstring instead of std::string.
As others have suggested, you could call CreateFileA directly, but I'd strongly suggest you not do this - you will end up with an unmaintanable collection of Unicode and non-Unicode function calls.
The problem is you are trying to pass char* to a function requiring wchar_t*
You could write a function to convert string into wstring:
wstring Widen( const string& str );
Then you could call CreateFile like this:
HANDLE hFile = CreateFile( Widen(filename).c_str(), etc. );
Another technique I've seen used is to conditionally define tstring to be either string or wstring depending on the Unicode setting, and use tstring everywhere in your code.
bool Open(tstring filename)
{
...
HANDLE hFile = CreateFile( filename.c_str(), etc. );
...
}
It's a bit of a thorny issue I'm afraid and the best solution for you is something only you can decide. However, I'd agree with Neil and steer clear of directly calling CreateFileA as that will leave you in a mess eventually.