LPCWSTR to char* and vice versa - c++

I'm working on a simple project with DirectX9. I'm having a little snag with some conversion of data types, and I've done some research, but haven't found anything particularly useful. Let's start with the code:
LPDIRECT3DSURFACE9 LoadSurface(char *fileName, D3DCOLOR transColor)
{
LPDIRECT3DSURFACE9 image = NULL;
D3DXIMAGE_INFO info;
HRESULT result;
result = D3DXGetImageInfoFromFile(fileName, &info);
if (result != D3D_OK) return NULL;
result = d3ddev->CreateOffscreenPlainSurface(
info.Width, //width of the surface
info.Height, //height of the surface
D3DFMT_X8R8G8B8, //surface format
D3DPOOL_DEFAULT, //memory pool use
&image, //reference to image
NULL); //reserved - ALWAYS NULL
//make sure file loaded properly
if (result != D3D_OK) return NULL;
return image;
}
At line 6, I'm getting the error for the variable fileName:
IntelliSense: argument of type "char *" is incompatible with parameter of type "LPCWSTR"
I also get the exact same error message at the second and third parameters when trying to use MessageBox's:
if (d3ddev == NULL)
{
MessageBox(hWnd, "Error Creating Direct3D Device", "Error", MB_ICONERROR);
return 0;
}
I've used code exactly like this before and had no problems. No idea what is going on - especially because LPCWSTR and char* are essentially the same thing...
Any help is appreciated!! Thank you

The most probable reason that you had no problem before is that you turned on unicode in Visual C++ project's settings. See the accepted answer here to turn it off again (if it's possible for you):
How do I turn off Unicode in a VC++ project?
Otherwise you need to convert char * to wchar_t * using MultiByteToWideChar function.

I've used code exactly like this before and had no problems.
No, you haven't.
LPCWSTR and char* are essentially the same thing...
No, they're not.
If you read the documentation, you'll see that a LPCWSTR is a const wchar_t*.
You should take a const wchar_t* into your function instead.
If you really want to convert to a char*, and don't mind that (at least in one of the two directions) this makes no sense, then you can read the answers to the following questions:
Convert char[] to LPCWSTR
How to convert char* to LPCWSTR?
… and apply const_cast afterwards. But, seriously, please don't.

Figured it out through looking through the DirectX header files... If anyone is having this same problem, rather than using the:
D3DXGetImageInfoFromFile(varName, &info);
Instead, use:
D3DXGetImageInfoFromFileA(varName, &info);
Same goes for MessageBox's... Use
MessageBoxA(handleVar, messageVar, titleVar, iconType);
*This comes with the caveat that your project property settings for character sets are set to Unicode. It becomes unnecessary if you switch that to Multi-byte.
As always, Thanks to those that actually contributed and helped me with this; and No Thanks to those who simply post on boards to ridicule or demean those who are less experienced - great use of your time.

Related

arg of type "const char *" is incompatible with parameter of type "LPSTR" c++

Hey guys I'm sorry to ask this but I haven't found my answer online. So i keep getting the error "arg of type "const char *" is incompatible with parameter of type "LPSTR"" when compiling one of my projects. How ever when i send it to my friend same code same everything he can compile it were both on windows 10 using visual studio 2017. Here is the Source code
void RunProcess()
{
runSetDebugPrivs();
while (!FindProcessName("csgo.exe", &__gameProcess)) Sleep(12);
while (!(getThreadByProcess(__gameProcess.th32ProcessID))) Sleep(12);
__HandleProcess = OpenProcess(PROCESS_ALL_ACCESS, false, __gameProcess.th32ProcessID);
while (__dwordClient == 0x0) __dwordClient = GetModuleNamePointer("client.dll", __gameProcess.th32ProcessID);
while (__dwordEngine == 0x0) __dwordEngine = GetModuleNamePointer("engine.dll", __gameProcess.th32ProcessID);
while (__dwordVGui == 0x0) __dwordVGui = GetModuleNamePointer("vguimatsurface.dll", __gameProcess.th32ProcessID);
__HWNDCss = FindWindow(NULL, "Counter-Strike: Global Offensive");
}
};
I think the problem is that the first parameter of GetModuleNamePointer function wants non-const char* string, but you put there const char* literal when you call the function. Literal constants are always const char*. The cause of this is probably the fact that other flavour of C language doesn't differentiate these in this condition. One possible fix is to change declaration of that function to accept LPCSTR (a.k.a. const char*) in the first parameter instead of LPSTR (a.k.a. char*).
You didn't show GetModuleNamePointer function, so I can only guess. If it is what I found on hack forums, it is declared like this:
DWORD GetModuleNamePointer(LPSTR LPSTRModuleName, DWORD __DwordProcessId);
But it can work with const safely, so you can simply change it to
DWORD GetModuleNamePointer(LPCSTR LPSTRModuleName, DWORD __DwordProcessId);
After this change in declaration it will be compatible with your compiler.
As already pointed out by #StoryTeller in comments, you can also disable the standard conformance in compiler. Here is description what it does and why it helps you: https://learn.microsoft.com/en-us/cpp/build/reference/permissive-standards-conformance
In short: Correct behavior is, maybe surprisingly, when your LPSTR program does't work. It works on older compilers, while new ones follow the standards more strictly. :-)
Answer taken from this forum entry. Go to Project "Properties -> C\C++ -> Language" and make sure the "Conformance mode" is set to "NO"

FindFirstFile cout problems

I need to find files with certain extentions, for example *.doc, *.docx
First, i'm looking for all files
lstrcat(szPath, L"*");
hFind = FindFirstFile(szPath, &fdFindData);
Then, i compare founded file with extention i need
PCWSTR str1 = L".doc";
if(NULL != StrStr(fdFindData.cFileName,str1)) {
FoundFileFunction(fdFindData.cFileName);
}
And then I got problem with cout
VOID FoundFileFunction(HANDLE hFile)
{
std::cout<<hFile;
}
This is output:
009AE50000
009AEB0000
009AEBBB00
and so on. What's the problem?
WIN32_FIND_DATA::cFileName is a TCHAR[MAX_PATH], not a HANDLE.
I don't know why you wrote HANDLE, as that's not uttered on the documentation page even once.
Your function is trying to print out the C-string filename as if it were a HANDLE, which is a different kind of pointer to a TCHAR*. It doesn't know to take the pointer as a TCHAR* so it doesn't know you want it to format the output as a string. It can only know to print the address represented by the pointer.
Your function FoundFileFunction should take a TCHAR*.
The problem would have been automatically detected had you used STRICT mode. If (for example) NO_STRICT is defined then HANDLE is an alias for void* which, per the rules of the language, can be initialised implicitly from a TCHAR*. You should always compile with STRICT defined: that would have changed the types not to be implicitly convertible to one another, and you would have received a compilation error for your mistake.
Furthermore, if your program is using Unicode, then TCHAR is not char but wchar_t, so you need to use not std::cout but std::wcout.

Safe C++ std::string to TCHAR * conversion?

I am trying to convert a std::string to a TCHAR* for use in CreateFile(). The code i have compiles, and works, but Visual Studio 2013 comes up with a compiler warning:
warning C4996: 'std::_Copy_impl': Function call with parameters that may be unsafe - this call relies on the caller to check that the passed values are correct. To disable this warning, use -D_SCL_SECURE_NO_WARNINGS. See documentation on how to use Visual C++ 'Checked Iterators'
I understand why i get the warning, as in my code i use std::copy, but I don't want to define D_SCL_SECURE_NO_WARNINGS if at all possible, as they have a point: std::copy is unsafe/unsecure. As a result, I'd like to find a way that doesn't throw this warning.
The code that produces the warning:
std::string filename = fileList->getFullPath(index);
TCHAR *t_filename = new TCHAR[filename.size() + 1];
t_filename[filename.size()] = 0;
std::copy(filename.begin(), filename.end(), t_filename);
audioreader.setFile(t_filename);
audioreader.setfile() calls CreateFile() internally, which is why i need to convert the string.
fileList and audioreader are instances of classes i wrote myself, but I'd rather not change the core implementation of either if at all possible, as it would mean I'd need to change a lot of implementation in other areas of my program, where this conversion only happens in that piece of code. The method I used to convert there was found in a solution i found at http://www.cplusplus.com/forum/general/12245/#msg58523
I've seen something similar in another question (Converting string to tchar in VC++) but i can't quite fathom how to adapt the answer to work with mine as the size of the string isn't constant. All other ways I've seen involve a straight (TCHAR *) cast (or something equally unsafe), which as far as i know about the way TCHAR and other windows string types are defined, is relatively risky as TCHAR could be single byte or multibyte characters depending on UNICODE definition.
Does anyone know a safe, reliable way to convert a std::string to a TCHAR* for use in functions like CreateFile()?
EDIT to address questions in the comments and answers:
Regarding UNICODE being defined or not: The project in VS2013 is a win32 console application, with #undef UNICODE at the top of the .cpp file containing main() - what is the difference between UNICODE and _UNICODE? as i assume the underscore in what Amadeus was asking is significant.
Not directly related to the question but may add perspective: This program is not going to be used outside the UK, so ANSI vs UNICODE does not matter for this. This is part of a personal project to create an audio server and client. As a result you may see some bits referencing network communication. The aim of this program is to get me using Xaudio and winsock. The conversion issue purely deals with the loading of the file on the server-side so it can open it and start reading chunks to transmit. I'm testing with .wav files found in c:/windows/media
Filename encoding: I read the filenames in at runtime by using FindFirstFileA() and FindNextFileA(). The names are retrieved by looking at cFilename in a WIN32_FIND_DATAA structure. They are stored in a vector<string> (wrapped in a unique_ptr if that matters) but that could be changed. I assume this is what Dan Korn means.
More info about the my classes and functions:
The following are spread between AudioReader.h, Audioreader.cpp, FileList.h, FileList.cpp and ClientSession.h. The fragment above is in ClientSession.cpp. Note that in most of my files i declare using namespace std;
shared_ptr<FileList> fileList; //ClientSession.h
AudioReader audioreader; //ClientSession.h
string _storedpath; //FileList.h
unique_ptr<vector<string>> _filenames; //FileList.h
//FileList.cpp
string FileList::getFullPath(int i)
{
string ret = "";
unique_lock<mutex> listLock(listmtx);
if (static_cast<size_t>(i) < _count)
{
ret = _storedpath + _filenames->at(i);
}
else
{
//rather than go out of bounds, return the last element, as returning an error over the network is difficult at present
ret = _storedpath + _filenames->at(_count - 1);
}
return ret;
}
unique_ptr<AudioReader_Impl> audioReaderImpl; //AudioReader.h
//AudioReader.cpp
HRESULT AudioReader::setFile(TCHAR * fileName)
{
return audioReaderImpl->setFile(fileName);
}
HANDLE AudioReader_Impl::fileHandle; //AudioReader.cpp
//AudioReader.cpp
HRESULT AudioReader_Impl::setFile(TCHAR * fileName)
{
fileHandle = CreateFile(fileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
if (fileHandle == INVALID_HANDLE_VALUE)
{
return HRESULT_FROM_WIN32(GetLastError());
}
if (SetFilePointer(fileHandle, 0, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER)
{
return HRESULT_FROM_WIN32(GetLastError());
}
return S_OK;
}
If you do not need to support the string containing UTF-8 (or another multi-byte encoding) then simply use the ANSI version of Windows API:
handle = CreateFileA( filename.c_str(), .......)
You might need to rejig your code for this as you have the CreateFile buried in a function that expects TCHAR. That's not advised these days; it's a pain to splatter T versions of everything all over your code and it has flow-on effects (such as std::tstring that someone suggested - ugh!)
There hasn't been any need to support dual compilation from the same source code since about 1998. Windows API has to support both versions for backward compatibility but your own code does not have to.
If you do want to support the string containing UTF-8 (and this is a better idea than using UTF-16 everywhere) then you will need to convert it to a UTF-16 string in order to call the Windows API.
The usual way to do this is via the Windows API function MultiByteToWideChar which is a bit awkward to use correctly, but you could wrap it up in a function:
std::wstring make_wstring( std::string const &s );
that invokes MultiByteToWideChar to return a UTF-16 string that you can then pass to WinAPI functions by using its .c_str() function.
See this codereview thread for a possible implementation of such a function (although note discussion in the answers)
The root of your problem is that you are mixing TCHARs and non-TCHARs. Even if you get it to work on your machine, unless you do it precisely right, it will fail when non-ASCII characters are used in the path.
If you can use std::tstring instead of regular string, then you won't have to worry about format conversions or codepage versus Unicode issues.
If not, you can use conversion functions like MultiByteToWideChar but make sure you understand the encoding used in the source string or it will just make things worse.
Try this instead:
std::string filename = fileList->getFullPath(index);
#ifndef UNICODE
audioreader.setFile(filename.c_str());
#else
std::wstring w_filename;
int len = MultiByteToWideChar(CP_ACP, 0, filename.c_str(), filename.length(), NULL, 0);
if (len > 0)
{
w_filename.resize(len);
MultiByteToWideChar(CP_ACP, 0, filename.c_str(), filename.length(), &w_filename[0], len);
}
audioreader.setFile(w_filename.c_str());
#endif
Alternatively:
std::string filename = fileList->getFullPath(index);
#ifndef UNICODE
audioreader.setFile(filename.c_str());
#else
std::wstring_convert<std::codecvt<wchar_t, char, std::mbstate_t>> conv;
std::wstring w_filename = conv.from_bytes(filename);
audioreader.setFile(w_filename.c_str());
#endif

Converting variables in Unicode

I'm a Javascript developer, so go easy on me! I am trying to write just a patch of C++ to enable printing on a framework. I'm compiling with Unicode, and based on my research, that is what is messing me up.
I think this is a relatively simple thing that I'm over complicating. The application has a std::string that contains the current printer name. The script first checks if it is unset (if it is it utilizes GetDefaultPrinter which outputs a LPTSTR). Finally, the script takes either than std::string or the LPTSTR and converts it to a LPCTSTR for CreateDC.
Here is my code:
std::string PrinterName = window->getPrinter();
LPDWORD lPrinterNameLength;
LPWSTR szPrinterName;
LPCTSTR PrinterHandle;
if (PrinterName == "unset") {
GetDefaultPrinter( szPrinterName, &lPrinterNameLength );
PrinterHandle = szPrinterName; //Note sure the best way to convert here
} else {
PrinterHandle = PrinterName.c_str();
}
HDC hdc = CreateDC( L"WINSPOOL\0", PrinterHandle, NULL, NULL);
When compiling, I only get conversions errors. Such as
Cannot convert parameter 2 from LPDWORD * to LPDWORD (GetDefaultPrinter)
and
Cannot convert from 'const char *' to 'LPCTSTR' (On the PrinterHandle = PrinterName.c_str() line)
I've done quite a bit of SO research on this, but haven't come up with a concrete solution.
Any help is greatly appreciated!
Even if you're compiled for "Unicode" (wide characters strings), you can call the "ANSI" (narrow characters strings) versions of the API functions. Windows will do the conversions for you and call the wide character version under the covers.
For example, for most Windows APIs like CreateDC, there isn't actually a function with that name. Instead, there's a macro named CreateDC that expands to either CreateDCA or CreateDCW, which are the actual function names. When you're compiled for "Unicode", the macros expand to the -W versions (which are the native ones in all modern versions of the OS. Nothing prevents you from explicitly calling either version, regardless of whether you're compiled for Unicode. In most cases, the -A version will simply convert the narrow strings to wide ones for you and then call the corresponding -W version. (There are some caveats here related to creating windows, but I don't think they apply to DCs.)
std::string PrinterName = window->getPrinter();
if (PrinterName == "unset") {
char szPrinterName[MAX_PATH]; // simplified for illustration
DWORD cchPrinterNameLength = ARRAYSIZE(szPrinterName);
GetDefaultPrinterA(szPrinterName, &cchPrinterNameLength);
PrinterName = szPrinterName;
}
HDC hdc = CreateDCA("WINSPOOL", PrinterName.c_str(), NULL, NULL);
First of all, as mentioned in the comments, the proper way is to make a DWORD and pass the address:
DWORD lpPrinterNameLength;
...
GetDefaultPrinter(..., &lpPrinterNameLength);
Why it's like that is so that it can use and change a number:
On input, specifies the size, in characters, of the pszBuffer buffer. On output, receives the size, in characters, of the printer name string, including the terminating null character.
It would just take a DWORD, but the function changes the number in the variable passed in, so the function needs the address of the variable to change in order for those changes to reflect back to the caller.
Secondly, since window->getPrinter() returns a narrow string and you're using UNICODE, which makes the functions take wide strings, you should convert from the narrow string into a wide one. There are several ways to do this (such as the really easy one mentioned in ildjarn's comment), and even this one is slightly better with C++11, though the aforementioned note applies even better with that, but I'll use MultiByteToWideChar and C++03:
std::wstring narrowToWide(const std::string &narrow) {
std::vector<wchar_t> wide;
int length = MultiByteToWideChar(CP_ACP, MB_ERR_INVALID_CHARS, narrow.c_str(), -1, NULL, 0);
if (!length) {
//error
}
wide.resize(length);
if (!MultiByteToWideChar(CP_ACP, MB_ERR_INVALID_CHARS, narrow.c_str(), -1, &wide[0], length)) {
//error, should probably check that the number of characters written is consistent as well
}
return std::wstring(wide.begin(), wide.end());
}
...
std::wstring PrinterName = narrowToWide(window->getPrinter());
//rest is same, but should be L"unset"
CreateDC( L"WINSPOOL\0", PrinterHandle, NULL, NULL);

Conversion problem from char * to wchar_t*

The below line works. It prints Success.
wchar_t * s1 = (wchar_t *) L"INSERT INTO OE(sqltext) VALUES('this text')";
if(WriteToSQL(s1) == 0)
printf( "Success"); //Success
else
printf( "Failed");
I need to take user input to create dynamic sql. I need to do what
L prefix is doing.
When i take input and do the required conversion, it does not work.
char input[100];
char sql[500];
printf("Enter input string :: ");
fgets(input,100,stdin);
for(int i=0;i<100;i++)
if(input[i]==10)
input[i]=0;
strcpy(sql,"INSERT INTO OE(sqltext) VALUES('");
strcat(sql,input);
strcat(sql,"')");
wchar_t wsql[500];
MultiByteToWideChar( CP_UTF8, 0, sql, strlen(sql),
wsql, strlen(sql) + 1 );
if(WriteToSQL(wsql) == 0)
printf( "Success");
else
printf( "Failed"); // It failed
Long conversassion but finally it did work. Hex memory dump and input from usta was most helpful. Thanks everybody for their time.
You can't just cast a char * to wchar_t * and expect it to work. You must do proper conversion, for example using MultiByteToWideChar function.
And in general, be very careful with type casts, and in particular avoid using C-style casts in C++ programs. This very case is a good example of why: you told the compiler to shut up ((SQLWCHAR *) sql), and in return got a problem at runtime. Use casts only when you are absolutely sure you are doing the right thing, and know better than the compiler. Not surprisingly, such cases are relatively rare...
Why not using wide chars the whole way?
Like this:
wchar_t input[100];
wchar_t sql[500];
wprintf(L"Enter input string :: ");
fgetws(input,100,stdin);
for(int i=0;i<100;i++)
if(input[i]==10)
input[i]=0;
wcscpy(sql,L"INSERT INTO OE(sqltext) VALUES('");
wcscat(sql,input);
wcscat(sql,L"')");
if(WriteToSQL(sql) == 0)
printf( "Success");
else
printf( "Failed"); // It failed
Warning:I did not test it, but it should work.
Manjoor, by using _tmain you opted using generic text so be consistent and try to stick to generic-text types throughout your program. That way your code will be cleaner and you won't need to use nasty string conversions like MultiByteToWideChar. If you are in position to change WriteToSQL function signature, pass argument 's' as SQLTCHAR* type. Declare sql and input variables as TCHAR arrays, use string routines from TCHAR.H (e.g. _tprintf instead printf, _T() macro for hardcoded strings...). For each routine you are using, go to its MSDN page and check Generic-text routine mappings to see which one you should use.
Google for Microsoft's support for UNICODE in order to better understand issue you had in the example you provided.