How to print array of LPCTSTR
example
LPCTSTR pszValueNames[] = { L"partnerID", L"partnerSubID", L"transactionID" };
for (int i = 0; i < (sizeof(pszValueNames) / sizeof(LPCWSTR)); i++)
{
cout << (*pszValueNames[i]) << endl;
}
Above give some numbers which is not real lpctstr values.
When i use wchar_t* and all other basic types it spit good values.
The reason why you get the address printed is that std::cout works with std::string, which is char based. An LPCWSTR is a wide string pointer type, and cout has no idea how to display wide strings "as strings".
You should use std::wcout to handle a wide string.
std::wcout << pszValueNames[i] << std::endl;
Also, your usage of LPCTSTR is not correct, even though your program may work. If you know you're using wide strings, specify LPCWSTR anywhere you would have used LPCTSTR. The reason is that LPCTSTR is not necessarily a wide string pointer type, depending on the type of build (MBCS or Unicode) that you are using.
So in a nutshell, your string pointer declarations are a hodge-podge of different string types, where some functions may work (if the LPCTSTR is a non-wide char pointer), while other string handling functions won't work.
Basically, if you're going to use LPCTSTR or LPTSTR, then all of your code that handles string or string pointer types should use "build-neutral" types, i.e. use LPCTSTR, TCHAR, LPTSTR, _T(), etc. These types will change seemlessly if you go from an MBCS build to a Unicode build (and vice-versa for whatever reason).
If on the other hand, if you know that the build will only ever be Unicode, then LPCWSTR and LPWSTR should be used throughout your program. Conversely, if you know and can guarantee that the build will only be MBCS, then use LPCSTR and LPSTR in your program.
The best thing to do is either use the build-neutral types (LPCTSTR, etc.) throughout your application, or change all of these to wide string types (LPCWSTR, etc.). The MBCS builds are becoming very rare these days, so might as well start developing using wide string types, and only use char string types in your application when you're interfacing to other functions that rely on char based strings.
Two issues. First, you're iterating over the wrong size:
for (int i = 0; i < (sizeof(pszValueNames) / sizeof(LPCWSTR)); i++)
// ^^^^^^^
That should be LPCTSTR. Or, to avoid this kind of error, just *pszValueNames. Or likely the reverse, LPCWSTR is the corret type but you declared the array to be LPCTSTR instead.
Secondly:
cout << (*pszValueNames[i]) << endl;
That would dereference the ith string - which would print only the first character. To print the whole string you don't need the dereference. Also, you would need to use wcout as cout does not work with wchar_t:
wcout << pszValueNames[i] << endl;
std::wcout was already mentioned, but I'd like to add that this is a nice example of how C++11 features can improve legacy or C-based code – if you can use a C++11 compiler, that is.
In C++11, you can write your loop like this:
for (auto const &name : pszValueNames)
{
std::wcout << name << std::endl;
}
No more sizeof or dereferencing issues to worry about. And if you later change your array to something like std::array<std::wstring> or std::vector<std::wstring> or std::set<std::wstring>, then the loop will not have to be modified at all (the element type of the container will just have to remain compatible with std::wcout).
edit: made code example use const &
The [] operator accesses the index*sizeof(type) part of the memory after the pointed mem. value, and this operator takes a pointer. You dont need the * there... *pszValue is dereferencing, true, but that is done implicitly here.... so you are actually dereferencing a value...
Quote from MSDN: "Usually, the value represented by postfix-expression is a pointer value, such as an array identifier, and expression is an integral value (including enumerated types). However, all that is required syntactically is that one of the expressions be of pointer type and the other be of integral type."
See the [] operator here
Related
How would I take...
string modelPath = "blah/blah.obj"
and concatenate it with...
L" not found."
While passing it in as LPCWSTR. I tried to do
(LPCWSTR)(modelPath + " was not found.").c_str()
However that did not work. Here is a larger example of what it looks like now.
if(!fin)
{
MessageBox(0, L"Models/WheelFinal.txt not found.", 0, 0); //
return;
}
LPCWSTR is a L ong P ointer to a C onstant W ide STR ing. Wide strings, at least in Win32, are 16 bits, whereas (const) char strings (i.e. (C)STR or their pointer-counterparts LP(C)STR) are 8 bits.
Think of them on Win32 as typedef const char* LPCSTR and typedef const wchar_t* LPCWSTR.
std::string is an 8-bit string (using the underlying type char by default) whereas std::wstring is a wider character string (i.e. 16-bits on win32, using wchar_t by default).
If you can, use std::wstring to concatenate a L"string" as a drop-in replacement.
A note on MessageBox()
Windows has a funny habit of defining macros for API calls that switch out underlying calls given the program's multibyte configuration. For almost every API call that uses strings, there is a FunctionA and FunctionW call that takes an LPCSTR or LPWCSTR respectively.
MessageBox is one of them. In Visual Studio, you can go into project settings and change your Multi-Byte (wide/narrow) setting or you can simply call MessageBoxA/W directly in order to pass in different encodings of strings.
For example:
LPWCSTR wideString = L"Hello, ";
MessageBoxW(NULL, (std::wstring(wideString) + L"world!").c_str(), L"Hello!", MB_OK);
LPCSTR narrowString = "Hello, ";
MessageBoxA(NULL, (std::string(narrowString) + "world!").c_str(), "Hello!", MB_OK);
If you can change modelPath to std::wstring, it becomes easy:
MessageBox(nullptr, (modelPath + L" not found.").c_str(), nullptr, 0);
I changed your 0 pointer values into nullptr as well.
Since std::string represents a narrow string, std::wstring represents a wide string, and the two are wildly different, casting from one representation to the other does not work, while starting with the appropriate one does. On the other hand, one can properly convert between representations using the new <codecvt> header in C++11.
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);
May I know how I can perform the following conversion?
// el.strCap is char[50]
// InsertItem is expecting TCHAR pointer (LPCTSTR)
// How I can perform conversion?
// I do not have access in both "list" and "el" source code
// Hence, there is no way for me to modify their signature.
list.InsertItem(i, el.strCap);
And No. I do not want to use
WideCharToMultiByte
They are too cumbersome to be used.
If you're using ATL, then you can use the various macros and helper classes that it includes to do the conversion:
char *test = "Hello World";
CA2CT ct(test);
list.InsertItem(i, ct);
Though saying WideCharToMultiByte is too cumbersome is a bit disingenious, in my opinion. It's easy enough to wrap a call to WideCharToMultiByte and make it return an std::wstring or whatever you need. In fact, that's basically what CA2CT is doing under the covers...
If your character string is encoded as ISO-8859-1, it's easy to convert to UTF-16:
// Convert an ISO-8859-1 string to a UTF-16 string
wchar_t wstr[50];
for (int i = 0; i < 50; ++i)
{
wstr[i] = el.strCap[i];
if (!wstr[i])
break;
}
But if your data is anything other then ISO-8859-1 (or ASCII which is a subset), then you will need to handle a more complex conversion. Once you need to do that, you will find that MultiByteToWideChar is not that cumbersome in comparison.
You could also use CStringW i.e. list.InsertItem(i, CStringW("blah"));
I'm trying to make changes to some legacy code. I need to fill a char[] ext with a file extension gotten using filename.Right(3). Problem is that I don't know how to convert from a CStringT to a char[].
There has to be a really easy solution that I'm just not realizing...
TIA.
If you have access to ATL, which I imagine you do if you're using CString, then you can look into the ATL conversion classes like CT2CA.
CString fileExt = _T ("txt");
CT2CA fileExtA (fileExt);
If a conversion needs to be performed (as when compiling for Unicode), then CT2CA allocates some internal memory and performs the conversion, destroying the memory in its destructor. If compiling for ANSI, no conversion needs to be performed, so it just hangs on to a pointer to the original string. It also provides an implicit conversion to const char * so you can use it like any C-style string.
This makes conversions really easy, with the caveat that if you need to hang on to the string after the CT2CA goes out of scope, then you need to copy the string into a buffer under your control (not just store a pointer to it). Otherwise, the CT2CA cleans up the converted buffer and you have a dangling reference.
Well you can always do this even in unicode
char str[4];
strcpy( str, CStringA( cString.Right( 3 ) ).GetString() );
If you know you AREN'T using unicode then you could just do
char str[4];
strcpy( str, cString.Right( 3 ).GetString() );
All the original code block does is transfer the last 3 characters into a non unicode string (CStringA, CStringW is definitely unicode and CStringT depends on whether the UNICODE define is set) and then gets the string as a simple char string.
First use CStringA to make sure you're getting char and not wchar_t. Then just cast it to (const char *) to get a pointer to the string, and use strcpy or something similar to copy to your destination.
If you're completely sure that you'll always be copying 3 characters, you could just do it the simple way.
ext[0] = filename[filename.Length()-3];
ext[1] = filename[filename.Length()-2];
ext[2] = filename[filename.Length()-1];
ext[3] = 0;
I believe this is what you are looking for:
CString theString( "This is a test" );
char* mychar = new char[theString.GetLength()+1];
_tcscpy(mychar, theString);
If I remember my old school MS C++.
You do not specify where is the CStringT type from. It could be anything, including your own implementation of string handling class. Assuming it is CStringT from MFC/ATL library available in Visual C++, you have a few options:
It's not been said if you compile with or without Unicode, so presenting using TCHAR not char:
CStringT
<
TCHAR,
StrTraitMFC
<
TCHAR,
ChTraitsCRT<TCHAR>
>
> file(TEXT("test.txt"));
TCHAR* file1 = new TCHAR[file.GetLength() + 1];
_tcscpy(file1, file);
If you use CStringT specialised for ANSI string, then
std::string file1(CStringA(file));
char const* pfile = file1.c_str(); // to copy to char[] buffer
I am writing a C++ DLL that is called by an external program.
1.) I take an array of strings (as char *var) as an argument from this program.
2.) I want to iterate through this array and call a COM function on each element of the string array. The COM function must take a BSTR:
DLL_EXPORT(void) runUnitModel(char *rateMaterialTypeNames) {
HRESULT hr = CoInitialize(NULL);
// Create the interface pointer.
IUnitModelPtr pIUnit(__uuidof(BlastFurnaceUnitModel));
pIUnit->initialiseUnitModel();
int i;
for(i=0; i < sizeOfPortRatesArray; i++)
pIUnit->createPort(SysAllocString(BSTR((const char *)rateMaterialTypeNames[i])));
I think its the SysAllocString(BSTR((const char *)rateMaterialTypeNames[i])) bit that is giving me problems. I get an access violation when the programs runs.
Is this the right way to access the value of the rateMaterialTypeName at i? Note I am expecting something like "IronOre" as the value at i, not a single character.
If you're using Microsofts ATL, you can use the CComBSTR class.
It will accept a char* and create a BSTR from it, also, you don't need to worry about deleting the BSTR, all that happens in the dtor for CComBSTR.
Also, see Matthew Xaviers answer, it doesn't look like you're passing your array of strings into that function properly.
Hope this helps
Because a variable holding a C string is just a pointer to the first element (a char*), in order to pass an array of C strings, the parameter to your function should be a char**:
DLL_EXPORT(void) runUnitModel(char **rateMaterialTypeNames)
This way, when you evaluate rateMaterialTypeNames[i], the result will be a char*, which is the parameter type you need to pass to SysAllocString().
Added note: you will also need to convert the strings to wide chars at some point, as Tommy Hui's answer points out.
If the parameter to the function rateMaterialTypeNames is a string, then
rateMaterialTypeNames[i]
is a character and not a string. You should use just the parameter name itself.
In addition, casts in general are bad. The conversion to a BSTR is a big flag. The parameter type for SysAllocString is
const OLECHAR*
which for 32-bit compilers is a wide character. So this will definitely fail because the actual parameter is a char*.
What the code needs is a conversion of narrow string to a wide string.
const OLECHAR* pOleChar = A2COLE( *pChar );
BSTR str = SysAllocString( pOleChar );
// do something with the 'str'
SysFreeString( str ); // need to cleanup the allocated BSTR