how to pass LPTSTR to a function and modify it's contents - c++

I need a function that is supplied a LPTSTR and an enumerated value, constructs a string based on the value and puts it in the LPTSTR.
I've written the following function which uses an array of names indexed by an enumerated value:
bool GetWinClassName(const int &WinType, LPTSTR *className, const int bufSize)
{
bool allOk = true;
LPTSTR tempName = new TCHAR[bufSize];
_stprintf_s(tempName, bufSize, TEXT("Win%sClass"), g_WinNames[WinType]);
std::cout << (char*)tempName << std::endl;
if (FAILED(StringCchCopy(*className, (bufSize+1)*sizeof(TCHAR), tempName)))
{
allOk = false;
}
delete[] tempName;
return allOk;
}
(Originally I just had the _stprintf_s line using className instead of tempName, this has been broken up to find where the error lies.)
The above code compiles in VC2010 Express but gives an unhandled exception: "Access violation writing" to (presumably) *className when it tries to execute the StringCchCopy line.
I can get this to work by doing
className = new TCHAR[bufSize];
before calling the function (with a matching delete[] after it) but do I really need to do that each time I want to call the function?
I understand where the problem lies but not why which is hampering my efforts to come up with a workable solution. The problem appears to me to be that I can't put something in the LPTSTR (via _stprintf_s or StringCchCopy) unless I allocate it some memory by using new TCHAR[bufSize]. I've tried assigning it an intial value of exactly the same size but with the same results which is leading me to think that the memory allocation actually has nothing to do with it. Is it then somehow casting my LPTSTR into a TCHAR[]? I don't see how that's possible but at this stage, I'd believe anything.
Can someone please explain what I'm doing wrong? (Or at least where my understanding is wrong.) And a probably related question is why is my std::cout only showing the first character of the string?

wstring winClassName( int const winType )
{
return wstring( L"Win" ) + g_WinNames[winType] + L"Class";
}
But I'm just completely baffled why you have that global array of names etc.: it's probably a design level error.

do I really need to do that each time I want to call the function?
An LPTSTR value is not a string object, it is simply a pointer-to-TCHAR. If you do not allocate a buffer, where do you think the characters will go? You must make sure that the className pointer argument points to a memory buffer that you can write to. Whether you allocate a new buffer each time is up to you.
As Alf implies, a better alternative is to avoid the direct use of pointers and dynamically allocated arrays altogether, and return a string object.
why is my std::cout only showing the first character of the string?
Use std::wcout instead if UNICODE is defined.

Related

Cannot safely delete LPTSTR allocation

Consider:
CCustomDateTime::CCustomDateTime()
{
LPTSTR result = new TCHAR[1024];
time_t _currentTime_t = time(0);
tm now;
localtime_s(&now, &_currentTime_t);
_tasctime_s(result, _tcslen(result), &now);
_currentTime = result;
delete[] result; // Error occurs here
}
CCustomDateTime::~CCustomDateTime()
{
}
__int64 CCustomDateTime::CurrentTimeAsInt64()
{
return _currentTime_t;
}
LPTSTR CCustomDateTime::CurrentTimeAsString()
{
return _currentTime;
}
I am unable to figure out the safest place to call delete[] on result.
If delete[] is ignored everything is fine, but otherwise an error occurs:
HEAP CORUPTION DETECTED at line delete[]
_tcslen(result) is not doing what you think it is.
change
_tasctime_s(result, _tcslen(result), &now);
to
_tasctime_s(result, 1024, &now);
There are a few problems with your code that I can see:
You don't check any of the function calls for errors. Don't ignore the return value. Use it to check for errors.
The second argument to _tasctime_s is the number of elements in the buffer provided. In other words, 1024. But you pass _tcslen(result) which is the length of the null-terminated string. Not only is that the wrong value, but result is at that point not initialised, so your code has undefined behaviour.
You assign a value to _currentTime, and then immediately delete that memory. So, _currentTime is a stale pointer. Any attempt to read from that memory is yet more undefined behaviour.
I don't want to tell you what your code should be, because you have only given us a tiny window into what you are trying to achieve. Dynamically allocating a fixed length array seems pointless. You may as well use automatically allocated storage. Of course, if you do want to return the memory to the caller, then dynamic allocation makes sense, but in that case then surely the caller would be responsible for calling delete[]. Since this code is clearly C++ I have to wonder why you are using raw memory allocation. Why not use standard library classes like std::string?
Looking at your update to the question, you could deallocate the memory in the destructor of your class. Personally though, I would recommend learning about the standard library classes that will greatly simplify your code.
_tcslen maps to strlen or wcslen depending on whether you are using ANSI or Unicode, respectively.
Both these functions return the length of a string, not the size of the buffer. In other words, they take a pointer to the first character of a string and continuously increment the pointer in search of a null terminator.
Calling these functions on an uninitialized buffer is undefined behavior because there's a very good chance that the pointer will get incremented out of the array bounds and elsewhere into the process' memory.

How to clear the buffer in a (char*)?

In my program I have a char* buffer which is being used inside a thread sequence which carries text from one function into another, but the text is different through the run-time in my program. The question that I am asking is, which function can I use to clear the previously used text out of the char* ?
For example, I have the following code:
int GameUtils::GetText(char *text)
{
for(int i=0; i<LINES_OF_TEXT; i++)
{
if(line[i][0]!=0)
{
strcpy(text, line[i]);
MessageBox(0, text, 0, 0);
line[i][0]=0;
return 1;
}
}
return 0;
}
line is defined as such: char GameUtils::line[2][32];
When the messagebox is output on the screen (while code is executed). I get some random junk characters in the text field. Can anyone tell me why this is?
Also! Note that line is assigned as stated in my previous question.
The function which assigns line is:
for (int x=0; x<((int)(strlen(szLine)+1)); x++)
{
if (szLine[x]==' ' || szLine[x]=='\0')
{
m=x;
for (y=0, z=n; z<m; y++, z++)
{
line[w][y]=szLine[z];
}
n=x+1;
w++;
}
}
The above function simply takes a parameter szLine[512] which is passed from my game interface and splits up the line assorting each space as a new parameter.
As an example, if inside the game the user states the line:
/msg <player> <message>
The function would assign each separate word to the line variable, respectively.
Such that, after the function is finished. line would look like
line[0] = /msg
line[1] = <player>
line[2] = <message>
So my question overall is as follows. Am I taking the cleaniest/most appropriate approach at this problem? If not, can anyone show me a better way to approach this problem? Also, can anyone explain to me why I am getting junk characters in the text parameter when the messagebox executes?
EDIT
After viewing the preview of my submitted question; I noticed I have defined char GameUtils::line[2][32] as a 2-dimensional array. I had done this earlier to test. I now understand this could have been the cause to my problem. Can anyone suggest me a replacement for this if I don't know the exact amount of parameters that could be inputted into this variable. The user can issue different requests each time like "/help ", "/msg ", "/whois ", "/create "...
When memory is allocated it isn't zeroed first (at least when using malloc, calloc - however, does zero memory first).
To clear a buffer in C (rather than C++), you have a few options:
Allocate the buffer using calloc instead of malloc.
Use Win32's ZeroMemory function
Use memset, like so: memset( buffer, 0x00, BUFFER_SIZE );
However you're clearly using C++, so you should use the standard library and C++ idioms rather than C-style things, that means using std::string instead of char*, and if you have to use buffers directly then the C++ way of zeroing (or filling) an array or buffer is std::fill.
First off, I would avoid using double dimensional arrays if you can avoid it. Maybe look into std::string:
http://www.cplusplus.com/reference/string/string/
As for why a char array might have "random junk" in it, when you allocate a buffer in C++, it always has data in it. You have to manually set the data to 0 if you want it to be empty. So when you first allocate an array, it might be a idea to zero out all the values first.

Adding two LPCWSTR variables

I'm trying to add two LPCWSTR Variables as in
Shader = L"shader.fx"
Path = L"Source/Shaders/"
return Path + Shader
I've tried a thousand different ways, but my latest has been this
LPCWSTR ShaderFile = GetShader(L"shader.fx");
....
LPCWSTR GetShader(std::wstring _Shader)
{
std::wstring ShaderPath = static_cast<std::wstring>(SHADER_DIRECTORY) + _Shader;
LPCWSTR Return = ShaderPath.c_str();
return Return;
}
Now when I put a break point on the return, the value seems fine, return = Source/Shaders/shader.fx as expected. But when I F10 back into my object, the ShaderFile variable turns out to be something completely random, a bunch of what seems like arabic symbols.
Could anyone point me in the right direction of what to do? As I said, the function seems to work fine, just when i F10 through the breakpoint back into my project the variable equals something completely different
What's happening is that you're returning an address to data that's being invalidated by the return, so everything will seem fine before the function returns, but immediately after the result, it's all (at least potentially) garbage.
If at all possible, just return the std::wstring, and somewhere in the calling code call its c_str() member function when you really need it in the form of a raw buffer.
If you can't do that, and simply must return the result as a raw LPCWSTR, then you'll probably have to allocate the space dynamically:
LPCWSTR *ret = new char [ShaderPath.size()];
strcpy(ret, ShaderPath.c_str());
return ret;
Then, the calling code will need to delete [] the memory when it's no longer needed.
You really want to avoid the latter, and just return an std::wstring though. It's much simpler and cleaner, and will save the nearly inevitable problems with either deleting the buffer before you're finished using it, or else forgetting to delete it when you are done using it (still serious problems in C, but essentially unheard of in decently written C++).
The wstring.c_str() returns the internal pointer of the string.
In your case the local variable is destroyed when you exit the function and hence the pointer returned is deallocated and you get unexpected result.
Possible solution would be to copy the string using the method wcscpy()
The problem is that the c_str() method is returning a pointer into the local variable ShaderPath's memory. When the function exits, ShaderPath is destroyed, along with the data pointed to by your LPCWSTR.
Why don't you just store the variable as a wstring, and whenever you need the LPCWSTR you can call c_str()?
std::wstring GetShader(std::wstring _Shader)
{
return static_cast<std::wstring>(SHADER_DIRECTORY) + _Shader;
}
Assuming you had a function Foo(LPCWSTR path), you would use it like:
Foo(GetShader(L"shader.fx").c_str());
or
std::wstring ShaderFile = GetShader(L"shader.fx");
Foo(ShaderFile.c_str());

Segmentation Fault on Assigning string Array

I have been trying to return an array of strings for a function for a couple of days to no avail. While I was searching around StackOverflow, I found that it would be a better idea to have a parameter that will be assigned the value of an array. So, here is my code example (not the actual usage, but a mockup of how I am trying to use the function). I am sorry if the code is a bit sloppy. I have been testing things out with it for a while.
void splitOn(string message, string delim, string***toCh) {
string** rString = new string*;
string lArr[numberOf(message, delim)+1];
for(int index=0; index<numberOf(message, delim)+2; index++) {
lArr[index]=message.substr(0, message.find(delim)).c_str();
message = message.substr(message.find(delim)+1, message.length());
rString[index]=&lArr[index];
cout << "IN LOOP "<<*rString[index]<<endl;
}
rString[numberOf(message, string(delim))] = &message;
toCh=&rString;
}
int main(){
string***arr;
splitOn("fox.over.lazy.dog", ".", arr);
cout << **arr[0]<<endl;
Note:
numberOf() takes a string and a delimiter(string) and returns how many times the delimiter is found within the string.
strings are from std::string
lArr (the local array within the loop) and *rString all give correct output.
Although I am trying to assign the array to a parameter, learning how to return an array is more appealing to me.
I could hack this together with a file and getLine(), but I would prefer to learn how to properly do this.
You're trying to return local variables, which will never work. You and your caller need to agree on how to allocate the return value. In C++ as the commenters mention this would normally be done by passing a reference to a vector to handle your allocation for you.
In C you have two options, you can either get the caller to pass in a big enough allocation, or use multiple calls to malloc in the callee (not forgetting the calls to free in the caller!)
For instance, if you pass a writable character array, you can simply overwrite the separator characters with null characters to split it up into individual strings without having to allocate new copies.

Casting string type with GetDlgItemText() for use as string buffer in C++

I am stumped by the behaviour of the following in my Win32 (ANSI) function:
(Multi-Byte Character Set NOT UNICODE)
void sOut( HWND hwnd, string sText ) // Add new text to EDIT Control
{
int len;
string sBuf, sDisplay;
len = GetWindowTextLength( GetDlgItem(hwnd, IDC_EDIT_RESULTS) );
if(len > 0)
{
// HERE:
sBuf.resize(len+1, 0); // Create a string big enough for the data
GetDlgItemText( hwnd, IDC_EDIT_RESULTS, (LPSTR)sBuf.data(), len+1 );
} // MessageBox(hwnd, (LPSTR)sBuf.c_str(), "Debug", MB_OK);
sDisplay = sBuf + sText;
sDisplay = sDisplay + "\n\0"; // terminate the string
SetDlgItemText( hwnd, IDC_EDIT_RESULTS, (LPSTR)sDisplay.c_str() );
}
This should append text to the control with each call.
Instead, all string concatenation fails after the call to GetDlgItemText(), I am assuming because of the typecast?
I have used three string variables to make it really obvious. If sBuf is affected then sDisplay should not be affected.
(Also, why is len 1 char less than the length in the buffer?)
GetDlgItemText() corretly returns the content of the EDIT control, and SetDlgItemText() will correctly set any text in sDisplay, but the concatenation in between is just not happening.
Is this a "hidden feature" of the string class?
Added:
Yes it looks like the problem is a terminating NUL in the middle. Now I understand why the len +1. The function ensures the last char is a NUL.
Using sBuf.resize(len); will chop it off and all is good.
Added:
Charles,
Leaving aside the quirky return length of this particular function, and talking about using a string as a buffer:
The standard describes the return value of basic_string::data() to be a pointer to an array whose members equal the elements of the string itself.
That's precisely what's needed isn't it?
Further, it requires that the program must not alter any of the values of that array.
As I understand it that is going to change along with the guarantee that all bytes are contiguous. I forget where I read a long article on this, but MS already implements this it asserted.
What I don't like about using a vector is that the bytes are copied twice before I can return them: once into the vector and again into the string. I also need to instantiate a vector object and a string object. That is a lot of overhead. If there were some string friendly of working with vectors (or CStrings) without resorting to old C functions or sopying characters one by one, I would use them. The string is very syntax friendly in that way.
The data() function on a std::string returns a const char*. You are not allowed to right into the buffer returned by it, it may be a duplicated buffer.
What you could do instead is to used a std::vector<char> as a temporary buffer.
E.g. (untested)
std::vector<char> sBuf( len + 1 );
GetDlgItemText( /* ... */, &sBuf[0], len + 1 );
std::string newText( &sBuf[0] );
newText += sText;
Also, the string you pass to SetDlgItemText should be \0 terminated so you should used c_str() not data() for this.
SetDlgItemText( /* ... */, newText.c_str() );
Edit:
OK, I've just checked the contract for GetWindowTextLength and GetDlgItemText. Check my edits above. Both will include the space for a null terminator so you need to chop it off the end of your string otherwise concatenation of the two strings will include a null terminator in the middle of the string and the SetDlgItemText call will only use the first part of the string.
There is a further complication in that GetWindowTextLength isn't guaranteed to be accurate, it only guarantees to return a number big enough for a program to create a buffer for storing the result. It is extremely unlikely that this will actually affect a dialog box item owned by the calling code but in other situations the actual text may be shorter than the returned length. For this reason you should search for the first \0 in the returned text in any case.
I've opted to just use the std::string constructor that takes a const char* so that it finds the first \0 correctly.
The standard describes the return value of basic_string::data() to be a pointer to an array whose members equal the elements of the string itself. Further, it requires that the program must not alter any of the values of that array. This means that the return value of data() may or may not be a copy of the string's internal representation and even if it isn't a copy you still aren't allowed to write to it.
I am far away from the win32 api and their string nightmare, but there is something in the code that you can check. Standard C++ strings do not need to be null terminated and nulls can happen anywhere within the string. I won't comment on the fact that you are casting away constantness with your C-style cast, which is a problem on its own, but rather on the strange effect you are
When you initially create the string you allocate extra space for the null (and initialize all elements to '\0') and then you copy the elements. At that point your string is len+1 in size and the last element is a null. After that you append some other string, and what you get is a string that will still have a null character at position len. When you retrieve the data with either data() (does not guarantee null termination!) or c_str() the returned buffer will still have the null character at len position. If that is passed to a function that stops on null (takes a C style string), then even if the string is complete, the function will just process the first len characters and forget about the rest.
#include <string>
#include <cstdio>
#include <iostream>
int main()
{
const char hi[] = "Hello, ";
const char all[] = "world!";
std::string result;
result.resize( sizeof(hi), 0 );
// simulate GetDlgItemText call
std::copy( hi, hi+sizeof(hi), const_cast<char*>(result.data()) ); // this is what your C-style cast is probably doing
// append
result.append( all );
std::cout << "size: " << result.size() // 14
<< ", contents" << result // "Hello, \0world!" - dump to a file and edit with a binary editor
<< std::endl;
std::printf( "%s\n", result.c_str() ); // "Hello, "
}
As you can see, printf expects a C-style string and will stop when the first null character is found, so that it can seem as if the append operation never took place. On the other hand, c++ streams do work properly with std::string and will dump the whole content, checking that the strings were actually appended.
A patch to your append operation disappearing would be removing the '\0' from the initial string (reserve only len space in the string). But that is not really a good solution, you should never use const_cast (there are really few places where it can be required and this is not one of them), the fact that you don't see it is even worse: using C style casts is making your code look nicer than it is.
You have commented on another answer that you do not want to add std::vector (which would provide with a correct solution as &v[0] is a proper mutable pointer into the buffer), of course, not adding the extra space for the '\0'. Consider that this is part of an implementation file, and the fact that you use or not std::vector will not extend beyond this single compilation unit. Since you are already using some STL features, you are not adding any extra requirement to your system. So to me that would be the way to go. The solution provided by Charles Bailey should work provided that you remove the extra null character.
This is NOT an answer. I have added it here as an answer only so that I can use formatting in a long going discussion about const_cast.
This is an example where using const_cast can break a running application:
#include <iostream>
#include <map>
typedef std::map<int,int> map_type;
void dump( map_type const & m ); // implemented somewhere else for concision
int main() {
map_type m;
m[1] = 10;
m[2] = 20;
m[3] = 30;
map_type::iterator it = m.find(2);
const_cast<int&>(it->first) = 10;
// At this point the order invariant of the container is broken:
dump(); // (1,10),(10,20),(3,30) !!! unordered by key!!!!
// This happens with g++-4.0.1 in MacOSX 10.5
if ( m.find(3) == m.end() ) std::cout << "key 3 not found!!!" << std::endl;
}
That is the danger of using const_cast. You can get away in some situations, but in others it will bite back, and probably hard. Try to debug in thousands of lines where the element with key 3 was removed from the container. And good luck in your search, for it was never removed.