I'm having trouble converting from LPSTR to const char* in MinGW under Windows.
#include <dirent.h>
#include <cstdio>
#include <fstream>
#include <windows.h>
int main() {
DIR *dir;
struct dirent *ent;
LPSTR buffer;
GetCurrentDirectory(100, buffer);
const char *str = *buffer;
dir = opendir(*str);
return 0;
}
What I'm trying to do is grab a list of all the current files in a directory and write it to a file; I can do the latter, but the former is giving me some trouble. I can figure out how to read the directory once I can convert the different variable types.
I know what LPSTR is, but I don't know how to apply it to this code.
Do not suggest using atlbase.h because MinGW does not support it, and I'm not willing to go back to Visual unless absolutely necessary.
You seem to be a bit confused about indirection. LPSTR is a char*. It is a pointer to a char (or, as is the case here, a pointer to the initial element of an array of char).
When you call GetCurrentDirectory, you need to pass it a pointer to the initial element of an array of char and the size of that array. So, what you need to do is declare an array and pass that into the function. For example,
char buffer[MAX_PATH];
GetCurrentDirectory(MAX_PATH, buffer);
With your current implementation, your program will assuredly crash because buffer is uninitialized, so GetCurrentDirectory will attempt to write to some random location in memory.
You should also check the return value of GetCurrentDirectory to ensure that it completed successfully and that the buffer contains the complete path. Its documentation explains the values that it may return.
Once you have the path, you can pass it directly to opendir: the array buffer is implicitly convertible to a pointer to its initial element--that is, the char[MAX_PATH] can be converted to a char*--and that char* can be implicitly converted to the char const* required by opendir:
DIR* dir = opendir(buffer);
Do note that the signature of GetCurrentDirectory depends on whether the UNICODE macro is defined or not: if you are compiling your program for Unicode, it actually takes a pointer to an array of wchar_t. If you build a Unicode program, you will need to account for this (you should use Unicode if you can).
Related
i am currently learning C++ and want to change my desktop wallpaper. However i am getting this error above.
#include <string>
#include <iostream>
#include <Windows.h>
using namespace std;
int main() {
LPWSTR test = L"C:\\Users\\user\\Pictures\\minion.png";
int result = SystemParametersInfo(SPI_SETDESKWALLPAPER, 0,
test, SPIF_UPDATEINIFILE);
}
A value of type "Const wchar_t*" cannot be used to initialize an entity of type LPWSTR
Any ideas?
Thanks
LPWSTR is an alias for wchar_t*, ie a pointer to a non-const character.
A string literal is a const array of characters, in your case a const wchar_t[35]. It decays into a pointer to a const character, pointing at the 1st character in the literal.
You can't assign a pointer-to-const to a pointer-to-non-const. That would allow writing access to read-only memory.
Use LPCWSTR instead, which is an alias for const wchar_t*.
LPCWSTR test = L"C:\\Users\\user\\Pictures\\minion.png";
The MSVC compiler is getting less and less permissive. On the whole that's a good thing.
L"C:\\Users\\user\\Pictures\\minion.png" is a literal of type const wchar_t[34] (the extra element is for the string terminator). That decays to a const wchar_t* pointer in certain circumstances.
LPWSTR is not a const pointer type so compilation will fail on a standard C++ compiler.
The solution is to use the const pointer type LPCWSTR.
Another way to resolve this compilation error is to set Conformance Mode to Default in the project Properties -> C/C++ -> Language. At least it worked in my VS2019 project.
I have a api function. I takes a pointer to array char. The calling function is out of my control. Array is dynamic but still need some checking
extern "C" int __stdcall calcW2(LPWSTR foo)
If somebody make a call with
char foo[5000];
LPSTR lpfoo2 = foo;
calcW2(lpfoo2 );
I understand that i need to make some checks. I can test for nulltpr. But if I want to len checking. That the char array has some validity. How is that best done? In the safest way for a string to 0 to 2500 chars. Do need check for something more?
if(foo != nullptr)
{
//Size checking
//size_t newsize = strlen(SerialNumber) + 1 not good?
std::wstring test(foo);
}
You missed one important point. The function signature says LPWSTR not LPSTR. This means that the function expects (or should expect) to receive wchar_t[] not char[]. See https://msdn.microsoft.com/en-us/library/cc230355.aspx.
I mean:
extern "C" int __stdcall calcW2(LPWSTR foo) <--- LP-W-STR
char foo[5000];
LPSTR lpfoo2 = foo; <--- LP-STR
calcW2(lpfoo2 ); <--- LP-STR passed into LP-W-STR ??
that should not compile. Argument types are wrong.
If you change the array to wchar_t[] and it starts to fail to compile, then most probably you have some _UNICODE #defines set wrong. In WINAPI and similar, many functions have dual definitions. When "UNICODE" flag is set, they take LPWSTR, but when the flag is cleared, the headers switch them to taking LPSTR. So if you see that it should be LPWSTR and you want it to be LPWSTR and it insists on being LPSTR, then you either messed up the function names, or UNICODE flag (or the header you have is simply incorrect).
char and wchar_t are different. Simplifying, char is "singlebyte" and wchar_t is "twobyte". Both use '\0' as the end-of-string marker, but in wchar_t that's actually '\0\0' since it's two bytes per character. Also, in wchar_t[] plain ASCII data isn't like a|b|c|d|e|f, it's 0|a|0|b|0|c|0|d|0|e|0|f since it's two bytes per character. That's why the strlen cannot work on 16bit encoded data properly - it picks the first \0 from the first character as end-of-string. Having a wchar_t data forcibly packed into char[] is plainly wrong or at least highly misleading and error-prone.
That's why you should use wstrlen instead, which so happens to take wchar_t* instead of char*.
This is a overall 'rule'. For any function working on char (strlen, strcat, strcmp, ..) you should be able to find relevant w* function (wstrlen, wstrcat, wstrcmp, ..). There may be some underscores in the names sometimes. Search the docs. Don't mix up char types. That't now just byte-array. There is some semantics out there for them, and usually if some types are named differently, there's a reason for that.
I've created a class to test some functionality I need to use. Essentially the class will take a deep copy of the passed in string and make it available via a getter. Am using Visual Studio 2012. Unicode is enabled in the project settings.
The problem is that the memcpy operation is yielding a truncated string. Output is like so;
THISISATEST: InstanceDataConstructor: Testing testing 123
Testing te_READY
where the first line is the check of the passed in TCHAR* string & the second line is the output from populating the allocated memory with the memcpy operation. Output expected is; "Testing testing 123".
Can anyone explain what is wrong here?
N.B. Got the #ifndef UNICODE typedefs from here: how-to-convert-tchar-array-to-stdstring
#ifndef INSTANCE_DATA_H//if not defined already
#define INSTANCE_DATA_H//then define it
#include <string>
//TCHAR is just a typedef, that depending on your compilation configuration, either defaults to char or wchar.
//Standard Template Library supports both ASCII (with std::string) and wide character sets (with std::wstring).
//All you need to do is to typedef String as either std::string or std::wstring depending on your compilation configuration.
//To maintain flexibility you can use the following code:
#ifndef UNICODE
typedef std::string String;
#else
typedef std::wstring String;
#endif
//Now you may use String in your code and let the compiler handle the nasty parts. String will now have constructors that lets you convert TCHAR to std::string or std::wstring.
class InstanceData
{
public:
InstanceData(TCHAR* strIn) : strMessage(strIn)//constructor
{
//Check to passed in string
String outMsg(L"THISISATEST: InstanceDataConstructor: ");//L for wide character string literal
outMsg += strMessage;//concatenate message
const wchar_t* finalMsg = outMsg.c_str();//prepare for outputting
OutputDebugStringW(finalMsg);//print the message
//Prepare TCHAR dynamic array. Deep copy.
charArrayPtr = new TCHAR[strMessage.size() +1];
charArrayPtr[strMessage.size()] = 0;//null terminate
std::memcpy(charArrayPtr, strMessage.data(), strMessage.size());//copy characters from array pointed to by the passed in TCHAR*.
OutputDebugStringW(charArrayPtr);//print the copied message to check
}
~InstanceData()//destructor
{
delete[] charArrayPtr;
}
//Getter
TCHAR* getMessage() const
{
return charArrayPtr;
}
private:
TCHAR* charArrayPtr;
String strMessage;//is used to conveniently ascertain the length of the passed in underlying TCHAR array.
};
#endif//header guard
A solution without all of the dynamically allocated memory.
#include <tchar.h>
#include <vector>
//...
class InstanceData
{
public:
InstanceData(TCHAR* strIn) : strMessage(strIn),
{
charArrayPtr.insert(charArrayPtr.begin(), strMessage.begin(), strMessage.end())
charArrayPtr.push_back(0);
}
TCHAR* getMessage()
{ return &charArrayPtr[0]; }
private:
String strMessage;
std::vector<TCHAR> charArrayPtr;
};
This does what your class does, but the major difference being that it does not do any hand-rolled dynamic allocation code. The class is also safely copyable, unlike the code with the dynamic allocation (lacked a user-defined copy constructor and assignment operator).
The std::vector class has superseded having to do new[]/delete[] in almost all circumstances. The reason being that vector stores its data in contiguous memory, no different than calling new[].
Please pay attention to the following lines in your code:
// Prepare TCHAR dynamic array. Deep copy.
charArrayPtr = new TCHAR[strMessage.size() + 1];
charArrayPtr[strMessage.size()] = 0; // null terminate
// Copy characters from array pointed to by the passed in TCHAR*.
std::memcpy(charArrayPtr, strMessage.data(), strMessage.size());
The third argument to pass to memcpy() is the count of bytes to copy.
If the string is a simple ASCII string stored in std::string, then the count of bytes is the same of the count of ASCII characters.
But, if the string is a wchar_t Unicode UTF-16 string, then each wchar_t occupies 2 bytes in Visual C++ (with GCC things are different, but this is a Windows Win32/C++ code compiled with VC++, so let's just focus on VC++).
So, you have to properly scale the size count for memcpy(), considering the proper size of a wchar_t, e.g.:
memcpy(charArrayPtr, strMessage.data(), strMessage.size() * sizeof(TCHAR));
So, if you compile in Unicode (UTF-16) mode, then TCHAR is expanded to wchar_t, and sizeof(wchar_t) is 2, so the content of your original string should be properly deep-copied.
As an alternative, for Unicode UTF-16 strings in VC++ you may use also wmemcpy(), which considers wchar_t as its "unit of copy". So, in this case, you don't have to scale the size factor by sizeof(wchar_t).
As a side note, in your constructor you have:
InstanceData(TCHAR* strIn) : strMessage(strIn)//constructor
Since strIn is an input string parameter, consider passing it by const pointer, i.e.:
InstanceData(const TCHAR* strIn)
I am using Visual Studio c++ and want to convert the Cstring to Byte. I have written this code but it gave me error in the second line that "data" is undefined.
CString data = _T( "OK");
LPBYTE pByte = new BYTE[data.GetLength() + 1];
memcpy(pByte, (VOID*)LPCTSTR(data), data.GetLength());
Further more I need to convert LPBYTE to const char for strcmp function. I have written the code but I can't find the issue with it.
const LPBYTE lpBuffer;
LPBYTE lpData = lpBuffer;
CString rcvValue(LPCSTR(lpBuffer));
const CHAR* cstr = (LPCSTR)rcvValue;
if (strcmp (cstr,("ABC")) == 0)
{
////
}
The CString type is a template specialization of CStringT, depending on the character set it uses (CStringA for ANSI, CStringW for Unicode). While you ensure to use a matching encoding when constructing from a string literal by using the _T macro, you fail to account for the different size requirements when copying the controlled sequence to the buffer.
The following code fixes the first part:
CString data = _T("OK");
size_t size_in_bytes = (data.GetLength() + 1) * sizeof(data::XCHAR);
std::vector<BYTE> buffer(size_in_bytes);
unsigned char const* first = static_cast<unsigned char*>(data.GetString());
unsigned char const* last = first + size_in_bytes;
std::copy(first, last, buffer.begin());
The second question is really asking to solve a solved problem. The CStringT type already provides a CStringT::Compare member, that can be used:
const LPBYTE lpBuffer;
CString rcvValue(static_cast<char const*>(lpBuffer));
if (rcvValue.Compare(_T("ABC")) == 0)
{
////
}
General advice: Always prefer using the concrete CStringT specialization matching your character encoding, i.e. CStringA or CStringW. The code will be much easier to read and reason about, and when you run into problems you need help with, you can post a question at Stack Overflow, without having to explain, what compiler settings you are using.
Make sure you include atlstr.h to provide the definition of CString, as below:
#include "stdafx.h"
#include <Windows.h>
#include <atlstr.h>
int _tmain(int argc, _TCHAR* argv[])
{
CString data = _T( "OK");
LPBYTE pByte = new BYTE[data.GetLength() + 1];
memcpy(pByte, (VOID*)LPCTSTR(data), data.GetLength());
return 0;
}
I'm fairly certain Jay is correct for your first question. You need to include the right header.
For your second question, why would you expect that code to work? Let's walk through what the code you've written actually does.
Create a char pointer (char *) without initializing it. This leaves lpData/lpBuffer pointing to a random location in memory.
Create a CString and initialize it with this random pointer.
Extract the buffer from the CString and compare it to a string literal.
Keeping in mind that the CString contains random garbage, what exactly do you expect this code to do? (Other than crash horribly? =) )
I also want to point out that you need to be more consistent in your approach to strings. Do you plan to support both char and wchar_t based strings as your use of TCHAR in the first sections suggests? Do you want to work with C-Style strings or do you want to use objects like CString? If you want to work with CString's, just use the Compare function that CString provides. Don't bother with strcmp.
Probably you didn't include the cruicial header
#include <afx.h>
int main()
{
CString data = _T( "OK");
LPBYTE pByte = new BYTE[data.GetLength() + 1];
memcpy(pByte, (VOID*)LPCTSTR(data), data.GetLength());
return 0;
}
This code works fine.
You should rather use
CString ss = "123ABC";
BYTE* bp = (BYTE*)ss.GetBuffer(ss.GetLength());
BYTE expected[16] ;
CopyMemory(expected,bp,sizeof(expected));
Just using '=' won't work.
I am trying to learn a little c++ and I have a silly question. Consider this code:
TCHAR tempPath[255];
GetTempPath(255, tempPath);
Why does windows need the size of the var tempPath? I see that the GetTempPath is declared something like:
GetTempPath(dword size, buf LPTSTR);
How can windows change the buf value without the & operator? Should not the function be like that?
GetTempPath(buf &LPTSTR);
Can somebody provide a simple GetTempPath implementation sample so I can see how size is used?
EDIT:
Thanks for all your answers, they are all correct and I gave you all +1. But what I meant by "Can somebody provide a simple GetTempPath implementation) is that i have tried to code a function similar to the one windows uses, as follow:
void MyGetTempPath(int size, char* buf)
{
buf = "C:\\test\\";
}
int main(int argc, char *argv[])
{
char* tempPath = new TCHAR[255];
GetTempPathA(255, tempPath);
MessageBoxA(0, tempPath, "test", MB_OK);
return EXIT_SUCCESS;
}
But it does not work. MessageBox displays a "##$' string. How should MyGetTempPath be coded to work properly?
Windows needs the size as a safety precaution. It could crash the application if it copies characters past the end of the buffer. When you supply the length, it can prevent that.
Array variables work like pointers. They point to the data in the array. So there is no need for the & operator.
Not sure what kind of example you are looking for. Like I said, it just needs to verify it doesn't write more characters than there's room for.
An array cannot be passed into functions by-value. Instead, it's converted to a pointer to the first element, and that's passed to the function. Having a (non-const) pointer to data allows modification:
void foo(int* i)
{
if (i) (don't dereference null)
*i = 5; // dereference pointer, modify int
}
Likewise, the function now has a pointer to a TCHAR it can write to. It takes the size, then, so it knows exactly how many TCHAR's exist after that initial one. Otherwise it wouldn't know how large the array is.
GetTempPath() outputs into your "tempPath" character array. If you don't tell it how much space there is allocated in the array (255), it has no way of knowing whether or not it will have enough room to write the path string into tempPath.
Character arrays in C/C++ are pretty much just pointers to locations in memory. They don't contain other information about themselves, like instances of C++ or Java classes might. The meat and potatoes of the Windows API was designed before C++ really had much inertia, I think, so you'll often have to use older C style techniques and built-in data types to work with it.
Following wrapper can be tried, if you want to avoid the size:
template<typename CHAR_TYPE, unsigned int SIZE>
void MyGetTempPath (CHAR_TYPE (&array)[SIZE]) // 'return' value can be your choice
{
GetTempPath(SIZE, array);
}
Now you can use like below:
TCHAR tempPath[255];
MyGetTempPath(tempPath); // No need to pass size, it will count automatically
In your other question, why we do NOT use following:
GetTempPath(buf &LPTSTR);
is because, & is used when you want to pass a data type by reference (not address). I am not aware what buf is typecasted to but it should be some pointer type.
Can somebody provide a simple
GetTempPath implementation sample so I
can see how size is used?
First way (based on MAX_PATH constant):
TCHAR szPath[MAX_PATH];
GetTempPath(MAX_PATH, szPath);
Second way (based on GetTempPath description):
DWORD size;
LPTSTR lpszPath;
size = GetTempPath(0, NULL);
lpszPath = new TCHAR[size];
GetTempPath(size, lpszPath);
/* some code here */
delete[] lpszPath;
How can windows change the buf value without the & operator?
& operator is not needed because array name is the pointer to first array element (or to all array). Try next code to demonstrate this:
TCHAR sz[1];
if ((void*)sz == (void*)&sz) _tprintf(TEXT("sz equals to &sz \n"));
if ((void*)sz == (void*)&(sz[0])) _tprintf(TEXT("sz equals to &(sz[0]) \n"));
As requested, a very simple implementation.
bool MyGetTempPath(size_t size, char* buf)
{
const char* path = "C:\\test\\";
size_t len = strlen(path);
if(buf == NULL)
return false;
if(size < len + 1)
return false;
strncpy(buf, path, size);
return true;
}
An example call to the new function:
char buffer[256];
bool success = MyGetTempPath(256, buffer);
from http://msdn.microsoft.com/en-us/library/aa364992(v=vs.85).aspx
DWORD WINAPI GetTempPath(
__in DWORD nBufferLength,
__out LPTSTR lpBuffer
);
so GetTempPath is defined something like
GetTempPath(DWORD nBufferLength, LPTSTR& lpBuffer);
What mean, that compiler passes the value lpBuffer by referenece.