I have a C++ program that is dynamically creating a query string which will then be passed to a SQLExecDirect call to connect to a database using ODBC. I'm having trouble passing the variable from one function to another, so I think I must be missing something basic?
In the ConstructQuery function (which returns type SQLWCHAR *), I have:
std::wstring test = L"test string"; //This test string will actually be several concatenated strings
SQLWCHAR *statement = (SQLWCHAR *)test.c_str();
std::wcout << statement;
return statement;
This prints the statement variable as expected. But when I pass the variable to my main function like this:
SQLStatement = ConstructQuery(SQLStatement);
std::wcout << SQLStatement;
I get no output.
If, instead of statement = (SQLWCHAR *)test.c_str();
I use: statement = L"test string";
The variable passes fine, but then I am not able to dynamically create the "test string" query in the earlier part of the function.
I was having a hard time finding out much about SQLWCHAR. I'm guessing that I may be converting std::wstring to SQLWCHAR * incorrectly? Another option would be to rewrite the function so that all of the wstring are SQLWCHAR * and do the concatenation that way - but I'm not sure that's possible and even if it was I don't think it's preferred?
You are returning a pointer to a local variable that goes out of scope at the end of the function ConstructQuery. It might be easiest to return a std::wstring by value and then work from there.
Related
I'm trying to write a function that displays the PID of the owning process of all threads in a system in multiple message boxes.
void CheckProcess()
{
LPCSTR blahzix;
HANDLE tsnap = CreateToolhelp32Snapshot (TH32CS_SNAPTHREAD, 0);
THREADENTRY32 tentry;
tentry.dwSize = sizeof (tentry);
BOOL CRec = Thread32First(tsnap, &tentry);
GetLastError();
while (CRec)
{
blahzix = tentry.th32OwnerProcessID;
MessageBox (NULL, NULL, blahzix, MB_OK);
CRec = Thread32Next(tsnap, &tentry);
}
CloseHandle(tsnap);
}
I was confused about why this wasn't working for a while so I opened it up in OllyDBG and found out that the code for MessageBoxwas having its third parameter receive the PID data directly instead of receiving an address which has the PID stored as a string, resulting in an access violation when the MessageBox function tries to access data stored at 00000004. If I remove the line blahzix = tentry.th32OwnerProcessID; and append the third line to look like this: LPCSTR blahzix = "anything"; then instead of crashing MessageBox properly displays a messagebox with the title anything.
Why does this happen? Am I correct in thinking that the compiler decides "variable blahzix isn't used anywhere except in this messagebox function and it always equals tentry.th32OwnerProcessID so they might as well be the same variable, I'll just get rid of it and make messagebox use that variable instead."
EDIT: Let me rephrase my question. If LPCSTR blahzix = "fdisaf"; uses the = operator and the = operator is supposed to change the value of the variable on the left to the value of the data or variable on the right, then how come it's use to create a string for blahzix is valid? Since blahzix is apparently actually a pointer I would assume the = operator should only change where the variable points to instead of changing the contents in it. How come using the = operator in this instance changes the data of the string that it points to and using it in this instance: blahzix = tentry.th32OwnerProcessID; changes the data of the pointer instead of the data of the string? Shouldn't the = operator change one or the other? How can I make the = operator specify which data I want to change?
THREADENTRY32::th32OwnerProcessID is a DWORD, not a string. Assigning it to a pointer and treating it as a string does not make sense. It's also invalid (a constraint violation without an explicit cast); I'm surprised how/why this even compiled.
Don't blame your own errors on the compiler. Compiler bugs are very, very rare.
blahzix = tentry.th32OwnerProcessID;
doesn't convert the integer process id to a string. It merely writes the process id as the address that blahzix points to. You don't own memory at this address so attempting to display a string from it results in undefined behaviour. A crash is likely.
To display the process id as a string via a MessageBox, you need to convert it to a char array. Given C++11 support you can do this by changing
blahzix = tentry.th32OwnerProcessID;
MessageBox (NULL, NULL, blahzix, MB_OK);
to
std::string s = std::to_string(tentry.th32OwnerProcessID);
char const *pchar = s.c_str();
MessageBox (NULL, NULL, pchar, MB_OK);
Alternatively, if you're limited to using C (the question is tagged as C++ but the code is all C), you could use
char str[12];
sprintf(str, "%d", tentry.th32OwnerProcessID);
MessageBox (NULL, NULL, str, MB_OK);
I tried to use this code:
USES_CONVERSION;
LPWSTR temp = A2W(selectedFileName);
but when I check the temp variable, just get the first character
thanks in advance
If I recall correctly, CString is typedef'd to either CStringA or CStringW, depending on whether you're building Unicode or not.
LPWSTR is a "Long Pointer to a Wide STRing" -- aka: wchar_t*
If you want to pass a CString to a function that takes LPWSTR, you can do:
some_function(LPWSTR str);
// if building in unicode:
some_function(selectedFileName);
// if building in ansi:
some_function(CA2W(selectedFileName));
// The better way, especially if you're building in both string types:
some_function(CT2W(selectedFileName));
HOWEVER LPWSTR is non-const access to a string. Are you using a function that tries to modify the string? If so, you want to use an actual buffer, not a CString.
Also, when you "check" temp -- what do you mean? did you try cout << temp? Because that won't work (it will display just the first character):
char uses one byte per character. wchar_t uses two bytes per character. For plain english, when you convert it to wide strings, it uses the same bytes as the original string, but each character gets padded with a zero. Since the NULL terminator is also a zero, if you use a poor debugger or cout (which is uses ANSI text), you will only see the first character.
If you want to print a wide string to standard out, use wcout.
In short: You cannot. If you need a non-const pointer to the underlying character buffer of a CString object you need to call GetBuffer.
If you need a const pointer you can simply use static_cast<LPCWSTR>(selectedFilename).
I know this is a decently old question, but I had this same question and none of the previous answers worked for me.
This, however, did work for my unicode build:
LPWSTR temp = (LPWSTR)(LPCWSTR)selectedFileName;
LPWSTR is a "Long Pointer to a Wide String". It is like wchar*.
CString strTmp = "temp";
wchar* szTmp;
szTmp = new WCHAR[wcslen(strTmp) + 1];
wcscpy_s(szTmp, wcslen(strTmp) + 1, strTmp);
I think I may be missing something really obvious here, but I have been struggling for way too long on this and my C++ is way rusty (10yrs+)
The code below works fine, but I need to be able to pass a variable into the query for lname. If I build the query in a string or char array I get an error that it is not compatible with parameter type of SQLWCHAR*
I know the code below is vulnerable to sql injection, but this is a one time hit on an isolated system, so I am really looking for simplicity more than anything else...
SQLHENV env;
SQLHDBC dbc;
SQLHSTMT sql_hStmt;
SQLRETURN ret;
SQLWCHAR outstr[1024];
SQLSMALLINT outstrlen;
SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &env);
SQLSetEnvAttr(env, SQL_ATTR_ODBC_VERSION, (void *) SQL_OV_ODBC3, 0);
SQLAllocHandle(SQL_HANDLE_DBC, env, &dbc);
ret = SQLDriverConnect(dbc, NULL, L"DSN=myDSN", SQL_NTS, NULL, 0, NULL, SQL_DRIVER_COMPLETE);
ret = SQLAllocHandle(SQL_HANDLE_STMT, dbc, &sql_hStmt);
SQLWCHAR* SQL = L"select * from DB.employees where lname='Smith'";
ret = SQLExecDirect(sql_hStmt, SQL, SQL_NTS);
SQLFetch(sql_hStmt);
There are two problems here, one is constructing a string containing the query you want, the other is passing that string as an argument to the function.
My recommendation is to stay as "C++" as possible until you reach these C boundaries. So we should use std::wstring for the string processing up until the point where it needs to be a C-style string:
std::wstring statementText = L"select * from DB.employees where lname='Smith'";
ret = SQLExecDirect(sql_hStmt, const_cast<SQLWCHAR*>(statementText.c_str()), SQL_NTS);
The c_str() member function returns a pointer to a null-terminated array (i.e., a C-style string), but this pointer has the type const wchar_t*; that is, the contents of this C-style string cannot be modified.
This is a problem because SQLWCHAR* is just wchar_t*; it doesn't make any promise to leave the data alone. That is why I included the const_cast, to remove the const from the c_str() value.
This is not something you generally want to do. const_cast is arguably the scariest cast because you directly open up the door to undefined behavior, as it's UB to modify a const object:
const int x = 0;
const int* p = &x; // anyone using this pointer can't modify x
int* bad = const_cast<int*>(p); // but this one is not so good
*bad = 5; // undefined behavior
The reason it's okay here, though, is that SQLExecDirect doesn't actually modify the string it's passed; it's simply an implementation error that const isn't used, so us taking that away is okay. (This lack of const mistake is very common in C.)
If you really need a buffer that can be modified, then starting in the current version of C++ (C++11) you can do this safely:
std::wstring statementText = L"select * from DB.employees where lname='Smith'";
ret = SQLExecDirect(sql_hStmt, &statementText[0], SQL_NTS);
We're taking the address of the first element, which itself is in a null-terminated array; another C-style string. This time, though, we have a modifiable array; the type already matches.
(The reason I make note this is okay in C++11 is that technically in the previous version, C++03, this behavior wasn't guaranteed. It was actually intended to be, but an error in wording in the standard made it not so. To be practical, you're fine either way.)
Whichever one you want to use is up to you. Some will argue to just use &str[0] all the time so we definitely have no UB, I would argue to document your intent and belief that the function doesn't modify the string and cast away const but ultimately operate in a const mindset. If something bad happens it's easy to relax away from const than it is to wish you had put it on.
One important thing to note is that all these returned pointers (either str.c_str() or &str[0]) are only good as long as the str object itself is alive and not modified. This is bad:
const wchar_t* get_query()
{
std::wstring result = /* build query */;
// oops, this pointer stops being meaningful when result stops existing!
return result.c_str();
}
With that all out of the way, building up these strings is easy. We have std::wstringstream:
std::wstringstream ss;
ss << "this is basically an expanding buffer that accepts anything std::wcout will";
ss << std::endl;
ss << "this includes integers " << 5 << " and other stream-insertable types";
So you probably want something like this:
std::wstring build_query(const std::wstring& name)
{
// you can provide a starting string
std::wstringstream result(L"select * from DB.employees where lname=");
result << "\'" << name << "\'";
return result.str(); // this captures the buffer as a C++ string
}
// Remember, this would be bad!
//
// SQLWCHAR* SQL = const_cast<SQLWCHAR*>(build_query(L"Smith").c_str());
//
// Because the C++ string returned by build_query is temporary;
// it stops existing at the end of this full expression,
// so SQL would be a bad pointer. This is right:
std::wstring SQL = build_query(L"Smith");
ret = SQLExecDirect(sql_hStmt, const_cast<SQLWCHAR*>(SQL.c_str()), SQL_NTS);
Hope that helps.
Also, I would avoid using all-upper identifiers except for macros, because such names are overwhelmingly expected to be macros by people reading C++ code. Additionally, I've used C++-style casts in my example code; you should do the same. The C-style cast ((type)value) is simply too powerful to be safe.
I suggest you PREPARE a paramererized query string. See here
If you simply concatenate strings to build a new query each time, you may be leaving your site open to an SQL injection attack
You can simply do it by :
You can do it by
int var = 10;
string str = to_string(var);
string requete="INSERT INTO stat(temps) VALUES (\"";
requete += str;
requete += "\")";
mysql_query(&mysql,requete.c_str());
just specify in mySql that the field has a type of int , double , float etc.
Thank you to The Beast. If you are recording two or more data, it can be used as follows.
int state;
string mesafe = to_string(getdata1);
string aci = to_string(getdata2);
string query = "INSERT INTO tarama (mesafe,aci) VALUES (\"";
query += mesafe;
query += "\",\"";
query += aci;
query += "\")";
qstate = mysql_query(conn, query.c_str());
I couldn't get over this problem for days. Now the problem is solved.
Im querying a sqlite db, but i need to convert the result (a TEXT attribute) to a C++ std::string. I feel like this should not be hard to accomplish, but im having trouble.
sqlite3_open("sqlite.db", &db);
std::string str = "SELECT something FROM table";
sqlite3_prepare_v2(db,
str.c_str(),
-1,
&m_statement,
0);
sqlite3_step(m_statement);
// OBS: 3rd party printf, cannot use std::cout in this environment
printf("Result1: %s",sqlite3_column_text(m_statement,0)); // OK! Result is printed
string try1 = string(
reinterpret_cast<const char*>(sqlite3_column_text(m_statement,0)));
printf("Result2: %s",try1); // null
stringstream ss;
ss << sqlite3_column_text(m_statement,0);
printf("Result3: %s",ss.str()); // null
Your problem isn't related to sqlite. When you use %s with printf, printf expects a char * NOT a std::string.
For example change this:
printf("Result2: %s",try1); // null
to
printf("Result2: %s",try1.c_str());
and see what happens.
C++ has two primary ways of implementing strings. The legacy C string (char*) and the std::string class found in the C++ standard library. If you deal with C APIs, you'll be dealing mostly with the former. printf and sqlite* are both from C APIs, so expect to deal with char*.
The problem is not with sqlite3_column_text.
printf format specifier %s expects a C string (char pointer).
As printf can't inspect what values are passed on the stack, so it has to trust the format specifier. Because the format specifier is %s, it reads an argument as it was a char pointer (it's not), but by coincidence, it's printing the wrong result, rather than crashing.
std::string exposes a function that gets you a read-only corresponding C string, so, for example, your the second case will be:
// Get a C string from std::string
printf("Result2: %s", try1.c_str());
My calls to the TRACE macro are resulting in an error when I attempt to pass a string to it like so:
TRACE(_T("PrintAppMsgTrace: %s"), _T(GetCmdIdStr( pMsg[APP_MSG_CODE_OFFSET] )));
This is the error I get in the console window output:
_CrtDbgReport: String too long or IO Error
Here is the prototype for GetCmdIdStr:
char * GetCmdIdStr( BYTE id );
GetCmdIdStr returns a pointer to memory containing something like "APP_ZDO_NLME_LEAVE_REQ". It essentially works like this:
char * GetCmdIdStr( BYTE id )
{
return "APP_ZDO_NLME_LEAVE_REQ";
}
Why am I getting this error? Any thoughts would be appreciated. Thanks.
The _T() macro is used on string literals. It expands to either just the original string literal, if you're compiling ANSI, or the string literal with an L prefix if you're compiling UNICODE. You can't apply it to the return value of a function.
If possible, the simplest thing to do would be to change the GetCmdIdStr function to return TCHAR instead of char:
TCHAR * GetCmdIdStr( BYTE id )
{
return _T("APP_ZDO_NLME_LEAVE_REQ");
}