TRACE Macro Error When Attempting to Pass String Variable - c++

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");
}

Related

Conversion (const char*) var goes wrong

I need to convert from CString to double in Embedded Visual C++, which supports only old style C++. I am using the following code
CString str = "4.5";
double var = atof( (const char*) (LPCTSTR) str )
and resutlt is var=4.0, so I am loosing decimal digits.
I have made another test
LPCTSTR str = "4.5";
const char* var = (const char*) str
and result again var=4.0
Can anyone help me to get a correct result?
The issue here is, that you are lying to the compiler, and the compiler trusts you. Using Embedded Visual C++ I'm going to assume, that you are targeting Windows CE. Windows CE exposes a Unicode API surface only, so your project is very likely set to use Unicode (UTF-16 LE encoding).
In that case, CString expands to CStringW, which stores code units as wchar_t. When doing (const char*) (LPCTSTR) str you are then casting from a wchar_t const* to a char const*. Given the input, the first byte has the value 52 (the ASCII encoding for the character 4). The second byte has the value 0. That is interpreted as the terminator of the C-style string. In other words, you are passing the string "4" to your call to atof. Naturally, you'll get the value 4.0 as the result.
To fix the code, use something like the following:
CStringW str = L"4.5";
double var = _wtof( str.GetString() );
_wtof is a Microsoft-specific extension to its CRT.
Note two things in particular:
The code uses a CString variant with explicit character encoding (CStringW). Always be explicit about your string types. This helps read your code and catch bugs before they happen (although all those C-style casts in the original code defeats that entirely).
The code calls the CString::GetString member to retrieve a pointer to the immutable buffer. This, too, makes the code easier to read, by not using what looks to be a C-style cast (but is an operator instead).
Also consider defining the _CSTRING_DISABLE_NARROW_WIDE_CONVERSION macro to prevent inadvertent character set conversions from happening (e.g. CString str = "4.5";). This, too, helps you catch bugs early (unless you defeat that with C-style casts as well).
CString is not const char* To convert a TCHAR CString to ASCII, use the CT2A macro - this will also allow you to convert the string to UTF8 (or any other Windows code page):
// Convert using the local code page
CString str(_T("Hello, world!"));
CT2A ascii(str);
TRACE(_T("ASCII: %S\n"), ascii.m_psz);
// Convert to UTF8
CString str(_T("Some Unicode goodness"));
CT2A ascii(str, CP_UTF8);
TRACE(_T("UTF8: %S\n"), ascii.m_psz);
Found a solution using scanf
CString str="4.5"
double var=0.0;
_stscanf( str, _T("%lf"), &var );
This gives a correct result var=4.5
Thanks everyone for comments and help.

Am I converting properly from "const char *" to "TCHAR*"?

I'm trying to pass a process name as a TCHAR to the following void:
void GetBaseAddressByName(DWORD pID, TCHAR *pN)
By doing it like this:
GetBaseAddressByName(aProcs[i], (TCHAR*)"Process.exe");
So my question is: is what I am doing correct? Because I have tried both TEXT("Process.exe") and _T("Process.exe") with my project's Character Set both on Multi-Bite and Unicode and it just tells me that
argument of type "const char*" is incompatible with parameter of type "TCHAR*"
The short answer is no. TCHAR maps to either char or wchar_t depending on your project's Unicode/Multi-byte setting. So, in general, a cast like that is either unnecessary or incorrect. The correct way, as you said, is to use either the TEXT or _T macro. The reason you're getting an error is that you're trying to pass a const character string to a function that expects a mutable character string. The safeset way to get around the error is to copy your constant string into a local TCHAR buffer and then pass that to GetBaseAddressByName.
It is better to have a TCHAR array first, then copy into it.
#include "atlstr.h"
char const * procName = "processName.exe";
TCHAR szName [128];
_tcscpy(szName, A2T(procName));
GetBaseAddressByName(aProcs[i], szName);
As suggested by #Remy Lebeau in the comments, procName can be defined as TCHAR const * procName = TEXT("processName.exe");.
(TCHAR*)"Process.exe" is not a valid type-cast. It will "work" when the project charset is set to ANSI/MBCS, but it will produce garbage if the charset is set to Unicode.
Using TEXT("Process.exe") is the correct way to make a string literal use TCHAR characters.
GetBaseAddressByName(aProcs[i], TEXT("Process.exe"));
However, you need to change your pN parameter to const TCHAR * (or LPCTSTR) instead:
void GetBaseAddressByName(DWORD pID, const TCHAR *pN);
void GetBaseAddressByName(DWORD pID, LPCTSTR pN);
A string literal is const data, and you cannot pass a pointer-to-const-data where a pointer-to-non-const-data is expected (without casting the const away with const_cast). That is why you were still getting errors when trying to use the TEXT()/_T() macros.
You need a L, like L"Process.exe". Unicode strings are specified with L"".
That said, there is no reason to use TCHAR. Use unicode all the time, if doing Windows work only.

TCHAR pointer initialization

I am trying to understand the following code:
const TCHAR * portName = "COM15";
I understand that a TCHAR is either a Char (in ANSI) or a wChar (in Unicode), basically a 1 byte or 2 byte container that represents something.
Now, if I declare a pointer to a const TCHAR called portName, portName is then a pointer. When I use the "=" sign, I am giving that pointer a value, and it seems irrational to me that "COM15" would be the address. I assume that line of code is giving me a pointer to the location of the beginning of the "COM15" string of characters, correct?
So what is actually happening in that line of code?
Is a string of characters ("COM15") being created and the "=" sign actually means that the location of the beginning of that string is being given to portName?
"Is a string of characters ("COM15") being created and the "=" sign actually means that the location of the beginning of that string is being given to portName?"
Yes, exactly. But other than it sounds from your question as you might have expected, this happens when the program is compiled, and not at run time. Also the const keyword prohibits changing that pointer at runtime later.
This how C works:
When you say char * str1 in C, you are allocating a pointer in the memory. When you write str1 = "Hello";, you are creating a string literal in memory and making the pointer point to it.
When you create another string literal "new string" and assign it to str1, all you are doing is changing where the pointer points.

how to convert or cast CString to LPWSTR?

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);

explain this macro

#define __T(x) L ## x
Found in code from one of the MFC source header file. It is mostly used for converting strings to ........ (I don't know what). If I am correct it converts strings to LPCTSTR...don't know what that type is either...
I can't seem to convert char* into LPCTSTR. While MFC file handling, the following code will always return error while trying to open the file...
char* filepath = "C:\\Program Files\\Microsoft Office\\Office12\\BITMAPS\\STYLES\\GLOBE.WMF";
if( !file.Open((LPCTSTR)filepath , CFile::modeRead, &fexp) )
{
fexp.ReportError();
return 1;
}
But instead if I wrote it this way, it doesn't give error:
if( !file.Open( _T("C:\\Program Files\\Microsoft Office\\Office12\\BITMAPS\\STYLES\\GLOBE.WMF") , CFile::modeRead, &fexp) )
{
fexp.ReportError();
return 1;
}
I am looking at passing a variable as the first argument to the CFile::Open() method.
The ## operator is a preprocessor concatenation operator. That is, this is valid code:
#define DECLARE_PTR(X) typedef std::auto_ptr<X> X##Ptr
DECLARE_PTR(int); // gets expanded to typedef std::auto_ptr<int> intPtr
intPtr i(new int(1));
In your case, the _T macro prepends the Long conversion symbol (L) to the input given. This only works with string literals. That means you can't write
char* str = "ABC";
wchar_t* wstr = _T(str); // error: Lstr is undefined
but you can safely write
char* str = "ABC";
LPTSTR wstr = _T("ABC"); // OK, gets expanded to wchar_t * wstr = L"ABC";
// when UNICODE is defined
// and char * wstr = "ABC"; when unicode is not defined
The L operator is a convertor of char and char* literals to a Long representation (from byte-wide representation to sizeof(wchar_t)-wide representation).
The macro is simply stringizing L with the argument so that:
_T("xyz")
becomes:
L"xyz"
This is the way to make a wstring but, in the non-Unicode versions, _T will map to nothing, so you'll get regular strings there.
_T() allows you to set up your string literals so that you can build as either Unicode or non-unicode.
In non-unicode builds it evaluates to nothing so a string literal is represented as "XYZ" which is a normal narrow string. In a unicode build it evaluates to L (L"XYZ") which tells the compiler that the string literal is a wide character string. This and the various "T" string typedefs LPCTSTR etc. Allow you to write code that builds correctly for unicode and non-unicode builds.
Note that google is your friend, simply typing _T into google gives several useful results...