Alright you all have been a tremendous help today and ive got one last question which will finish my program and I am hoping wont be difficult to answer.
What I want to do is grab the users temp folder path and save it to an std::string.
I was able to find this link: http://msdn.microsoft.com/en-us/library/aa364992%28VS.85%29.aspx
The only issue with the link is I dont understand how to take that and save it to a string.
std::wstring strTempPath;
wchar_t wchPath[MAX_PATH];
if (GetTempPathW(MAX_PATH, wchPath))
strTempPath = wchPath;
Change wstring to string, wchar_t to char and GetTempPathW to GetTempPathA if you're not using Unicode.
This function seems to use a C-Style String. However, you can convert it to a C++ String.
#define MAX_LENGTH 256 // a custom maximum length, 255 characters seems enough
#include <cstdlib> // for malloc and free (optional)
#include <string>
using namespace std;
// other code
char *buffer = malloc(MAX_LENGTH);
string temp_dir;
if (GetTempPath(MAX_LENGTH, buffer) != 0) temp_dir = string(buffer);
else {/* GetTempPath returns 0 on error */}
free(buffer); // always free memory used for the C-Style String
// other code
You can also allocate and free memory using new[] and delete[] if you find it easier! You can use static memory allocation too!
I hope this helps... :D
Related
I have following code in C++ (wrote in Visual Studio 2010).
void TEST(BYTE data[], int size)
{
wstring aData = L"Here is my string";
//something code to append aData string to data array
WinHttpClient client(url);
// Send HTTP post request.
client.SendHttpRequest(L"POST");
}
How can i append aData string to data BYTE array.
Short answer: You can't.
So you get passed the BYTE[] and the size, but you don't know if the data is on the stack or heap, so you can't just use realloc or something to make it bigger.
One approach is to make sure the array is bigger than you need, and pass the current and max size.
Another approach would be to change the API to allow you to use realloc or similar to resize the array.
The only way I can think of without changing the API is to use some sort of marker in data to delimit used and unused space (doesn't work for binary data). e.g. 0 means unused, so you can just look for the first 0 and start appending from there.
edit
Perhaps I misread the intent. If you don't want to make a permanent change, you could take a local copy, append to that (and make sure you clean it up). I thought you wanted a permanent, "in place" append.
#include "stdafx.h"
#include <iostream>
using namespace std;
#include <boost/locale/encoding_utf.hpp>
std::wstring utf8_to_wstring(const std::string& str)
{
return utf_to_utf<wchar_t>(str.c_str(), str.c_str() + str.size());
}
int main()
{
unsigned char test[10];
std::string tesStr((char*)test);
wstring temp = utf8_to_wstring(tesStr);
}
I'm writing a Win32 console application in Visual Studio 2010.
Consider one function that take two char* as parameters.
Following is prototype of function:
void WriteApplicationFile(char *mappname,char* MessageString)
{
//Do some File related stuffs.
}
Now the following calls are working perfectly:
WriteApplicationFile("FirstOne", "Append Me");
WriteApplicationFile("FirstOne", "Append Another");
But if I try the same thing with some character array thing this will give me assertion, and throw me on assembly.
The following code is not working:
char * LocalBuffer = new char[100];
sprintf(LocalBuffer,"Number of jobs in Queue %d",JobsCount);
WriteApplicationFile("SAAZshadowProtect",LocalBuffer);
free(LocalBuffer);
LocalBuffer = NULL;
//Work fine.
//...
LocalBuffer = new char[100];
sprintf(LocalBuffer,"Log file name %s",LogFileCharName);
WriteApplicationFile("SAAZshadowProtect",LocalBuffer);
free(LocalBuffer); // I got assertion here..
LocalBuffer = NULL;
Where am I going wrong?
One more thing is that I want to handle all assertion and bugs with try-catch block. How would I do this?
If use new[] you must use delete[], not free() or delete. Replace:
free(LocalBuffer);
with:
delete[] LocalBuffer;
There appears to be no reason to be dynamically allocating memory. The size of the buffer is a compile time constant, is not large (no stack overflow) and the buffer appears to not be required to live beyond the scope in which it was allocated.
As this is c++ strongly suggest using std::string which will handle dynamic memory management for you and std::ostringstream which is typesafe and avoids specification of fixed sized buffers instead of sprintf():
#include <sstream>
#include <string>
std::ostringstream out;
out << "Number of jobs in Queue " << JobsCount;
const std::string s(out.str());
If access to a c-style string is required use std::string::c_str().
Additionally, the argument types of WriteApplicationFile() are char*, not const char*, so passing a string literal to the function would be causing undefined behaviour if the function modifies the arguments.
First, are you programming in C or in C++. The code you present
looks like C, but you speak of a try/catch block, which can only
be C++.
In C++, use std::ostringstream and std::string. Any other
solution is simply incorrect.
In C, you should use snprintf, instead of sprintf. It is
almost impossible to use sprintf safely. (How many characters
are in LogFileCharName, for example.) And don't use dynamic
allocation when you don't have to. (That holds for C++ as
well; there should be no new or delete (nor malloc nor
free) in the code you show.
As to what is going wrong, there are at least two possible
problems in the code you show: you're allocating memory with
new[], but freeing it with free (undefined behavior), and
you're not checking the length of LogFileCharName before
calling sprintf, so you could be overwriting the end of the
buffer.
I know there is a similarly titled question already on SO but I want to know my options for this specific case.
MSVC compiler gives a warning about strcpy:
1>c:\something\mycontrol.cpp(65): warning C4996: 'strcpy': This function or
variable may be unsafe. Consider using strcpy_s instead. To disable
deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details.
Here's my code:
void MyControl::SetFontFace(const char *faceName)
{
LOGFONT lf;
CFont *currentFont = GetFont();
currentFont->GetLogFont(&lf);
strcpy(lf.lfFaceName, faceName); <--- offending line
font_.DeleteObject();
// Create the font.
font_.CreateFontIndirect(&lf);
// Use the font to paint a control.
SetFont(&font_);
}
Note font_ is an instance variable. LOGFONT is a windows structure where lfFaceName is defined as TCHAR lfFaceName[LF_FACESIZE].
What I'm wondering is can I do something like the following (and if not why not):
void MyControl::SetFontFace(const std::string& faceName)
...
lf.lfFaceName = faceName.c_str();
...
Or if there is a different alternative altogether then let me know.
The reason you're getting the security warning is, your faceName argument could point to a string that is longer than LF_FACESIZE characters, and then strcpy would blindly overwrite whatever comes after lfFaceName in the LOGFONT structure. You do have a bug.
You should not blindly fix the bug by changing strcpy to strcpy_s, because:
The *_s functions are unportable Microsoft inventions almost all of which duplicate the functionality of other C library functions that are portable. They should never be used, even in a program not intended to be portable (as this appears to be).
Blind changes tend to not actually fix this class of bug. For instance, the "safe" variants of strcpy (strncpy, strlcpy, strcpy_s) simply truncate the string if it's too long, which in this case would make you try to load the wrong font. Worse, strncpy omits the NUL terminator when it does that, so you'd probably just move the crash inside CreateFontIndirect if you used that one. The correct fix is to check the length up front and fail the entire operation if it's too long. At which point strcpy becomes safe (because you know it's not too long), although I prefer memcpy because it makes it obvious to future readers of the code that I've thought about this.
TCHAR and char are not the same thing; copying either a C-style const char * string or a C++ std::string into an array of TCHAR without a proper encoding conversion may produce complete nonsense. (Using TCHAR is, in my experience, always a mistake, and the biggest problem with it is that code like this will appear to work correctly in an ASCII build, and will still compile in UNICODE mode, but will then fail catastrophically at runtime.)
You certainly can use std::string to help with this problem, but it won't get you out of needing to check the length and manually copy the string. I'd probably do it like this. Note that I am using LOGFONTW and CreateFontIndirectW and an explicit conversion from UTF-8 in the std::string. Note also that chunks of this were cargo-culted out of MSDN and none of it has been tested. Sorry.
void MyControl::SetFontFace(const std::string& faceName)
{
LOGFONTW lf;
this->font_.GetLogFontW(&lf);
int count = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS,
faceName.data(), faceName.length(),
lf.lfFaceName, LF_FACESIZE - 1)
if (count <= 0)
throw GetLastError(); // FIXME: use a real exception
lf.lfFaceName[count] = L'\0'; // MultiByteToWideChar does not NUL-terminate.
this->font_.DeleteObject();
if (!this->font_.CreateFontIndirectW(&lf))
throw GetLastError(); // FIXME: use a real exception
// ...
}
lf.lfFaceName = faceName.c_str();
No you shouldn't do that because you are making a local copy of the poitner to the data held inside the std::string. If the c++ string changes, or is deleted, the pointer is no longer valid, and if lFaceName decides to change the data this will almost certainly break the std::string.
Since you need to copy a c string, you need a 'c' function, then strcpy_s (or it's equivalent) is the safe alternative
Have you tried? Given the information in your post, the assignment should generate a compiler error because you're trying to assign a pointer to an array, which does not work in C(++).
#include <cstdio>
#include <string>
using namespace std;
struct LOGFONT {
char lfFaceName[3];
};
int main() {
struct LOGFONT f;
string foo="bar";
f.lfFaceName = foo.c_str();
return 0;
}
leads to
x.c:13: error: incompatible types in assignment of `const char*' to `char[3]'
I'd recommend using a secure strcpy alternative like the warning says, given that you know the size of the destination space anyway.
#include <algorithm>
#include <iostream>
#include <string>
enum { LF_FACESIZE = 256 }; // = 3 // test too-long input
struct LOGFONT
{
char lfFaceName[LF_FACESIZE];
};
int main()
{
LOGFONT f;
std::string foo("Sans-Serif");
std::copy_n(foo.c_str(), foo.size()+1 > LF_FACESIZE ? LF_FACESIZE : foo.size()+1,
f.lfFaceName);
std::cout << f.lfFaceName << std::endl;
return 0;
}
lf.lfFaceName = faceName.c_str(); won't work for two reasons (assuming you change faceName to a std:string)
The lifetime of the pointer returned by c_str() is temporary. It's only valid as long as the fileName object doesn't change and in alive.
The line won't compile. .c_str() returns a pointer to a char, and lfFaceName is a character array and can't be assigned to. You need to do something to fill in the string array, to fill in the bytes at lfFaceName, and pointer assignment doesn't do that.
There isn't anything C++ that can help here, since lfFaceName is a C "string". You need to use a C string function, like strcpy or strcpy_s. You can change your code to:
strcpy_s(lf.lfFaceName, LF_FACESIZE, faceName);
I've created a program in C++ that prompts the user for a filename and for the requested filesize. The program checks if the requested filesize is bigger than the actual filesize and then adds null characters (the ones with code 0) at the end of the file, until the requested filesize is reached.
I have done it like this (with fstream):
for (blah blah) {
file << '\0'; // ('file' is an fstream object)
}
and it worked just as I wanted it to. I know this is a bad code as it may torture the hard disk by sending many calls to it (and it's slow by the way). This was only for testing reasons. Then, because of this problem I decided to create a variable storing the NUL characters and save the whole variable to the file at once (without saving each character separately).
Then the problem appeared... because of the NUL character (also known as null-terminator), terminating the string, I couldn't store those zeros in any way.
I've tried an array of chars, a string and even a stringstream, but none worked (there's something interesting about stringstream, when I used it, the file's content looked like this: 0x47c274). Anyway, it didn't work as I expected it to.
Is there any efficient way of storing an array of null characters?
Store them in an array of characters and use ostream::write to write the array to the file.
Here's an example:
#include <algorithm>
#include <iostream>
#include <fstream>
using namespace std;
int main()
{
ofstream fout("pokemon");
char buffer[1000];
std::fill(buffer, buffer + 1000, '\0');
fout.write(buffer, sizeof(char) * 1000);
return 0;
}
Many windows APIs take a pointer to a buffer and a size element but the result needs to go into a c++ string. (I'm using windows unicode here so they are wstrings)
Here is an example :-
#include <iostream>
#include <string>
#include <vector>
#include <windows.h>
using namespace std;
// This is the method I'm interested in improving ...
wstring getComputerName()
{
vector<wchar_t> buffer;
buffer.resize(MAX_COMPUTERNAME_LENGTH+1);
DWORD size = MAX_COMPUTERNAME_LENGTH;
GetComputerNameW(&buffer[0], &size);
return wstring(&buffer[0], size);
}
int main()
{
wcout << getComputerName() << "\n";
}
My question really is, is this the best way to write the getComputerName function so that it fits into C++ better, or is there a better way? I don't see any way to use a string directly without going via a vector unless I missed something? It works fine, but somehow seems a little ugly. The question isn't about that particular API, it's just a convenient example.
In this case, I don't see what std::vector brings to the party. MAX_COMPUTERNAME_LENGTH is not likely to be very large, so I would simply use a C-style array as the temporary buffer.
See this answer to another question. It provides the source to a StringBuffer class which handles this situation very cleanly.
I would say, since you are already at task of abstracting Windows API behind a more generic C++ interface, do away with vector altogether, and don't bother about wstring constructor:
wstring getComputerName()
{
wchar_t name[MAX_COMPUTERNAME_LENGTH + 1];
DWORD size = MAX_COMPUTERNAME_LENGTH;
GetComputerNameW(name, &size);
return name;
}
This function will return a valid wstring object.
I'd use the vector. In response to you saying you picked a bad example, pretend for a moment that we don't have a reasonable constant upper bound on the string length. Then it's not quite as easy:
#include <string>
#include <vector>
#include <windows.h>
using std::wstring;
using std::vector;
wstring getComputerName()
{
DWORD size = 1; // or a bigger number if you like
vector<wchar_t> buffer(size);
while ((GetComputerNameW(&buffer[0], &size) == 0))
{
if (GetLastError() != ERROR_BUFFER_OVERFLOW) aargh(); // handle error
buffer.resize(++size);
};
return wstring(&buffer[0], size);
}
In practice, you can probably get away with writing into a string, but I'm not entirely sure. You certainly need additional guarantees made by your implementation of std::wstring, beyond what's in the standard, but I expect MSVC's strings are probably OK.
I think that if wstring::reference is wchar_t& then you're sorted. 21.3.4 defines that non-const operator[] returns a reference, and that it returns data()[pos]. So if reference is just a plain wchar_t& then there's no scope for exciting copy-on-write behaviour through the reference, and the string must in fact be modifiable through the pointer &buffer[0]. I think. The basic problem here is that the standard allowed implementations more flexibility than turned out to be needed.
That's a lot of effort and commenting though, just to avoid copying a string, so I've never felt the need to avoid an intermediate array/vector.