strstr - string.h miscommunication error? - c++

I am trying to compare the file name against a list of strings to see if they match up and if they do then return accordingly
I am using the following condition:
if (strstr(file, str) != NULL) {
return 1;
}
Though MSVC++2012 prompts me with the following error on strstr:
Error: no instance of overloaded function "strstr" matches the argument list
argument types are: (WCHAR [260], char *)
The question is: what is the meaning of the error above and how could it be fixed?

The problem you have got comes out from the fact that the strstr function expects to see two char pointers (char *) as its arguments, but it receives the WCHAR array instead as the first argument.
Unlike the usual 8-bit char, WCHAR represents a 16-bit Unicode character.
The one way to fix your error is to convert your Unicode file name to the char array as following:
char cfile[260];
char DefChar = ' ';
WideCharToMultiByte(CP_ACP, 0, file, -1, cfile, 260, &DefChar, NULL);
And then use cfile instead of file.
But this approach will only work with ASCII characters.
For that reason, you could consider using another string comparison method, suitable for the WCHAR strings (wstring).
The following code might help you with that second approach:
// Initialize the wstring for file
std::wstring wsfile (file);
// Initialize the string for str
std::string sstr(str);
// Initialize the wstring for str
std::wstring wstr(sstr.begin(), sstr.end());
// Try to find the wstr in the wsfile
int index = wsfile.find(wstr);
// Check if something was found
if(index != wstring::npos) {
return 1;
}
The good SO answer about usage of the find method in std::wsting: Find method in std::wstring.
More on converting string to wstring: Mijalko: Convert std::string to std::wstring.
Please leave some feedback in comments if it does not help.

Related

Getting Sapi to say a string

I have a program that asks a person to have the text they want to have translated into Al Bhed, which is just a cipher where the letters are moved around,and have the SAPI say it. the string translates fine, but this piece of code:
hr = pVoice->Speak(sTranslated, 0, NULL);
will not work, because it says "no suitable conversion function from 'std::string' to 'const WCHAR*' exists.
All I want is for the voice to say the translated string. How do I go about this?
First you need to convert the std::string content, which uses type char, into a std::wstring, which uses type wchar_t. This is due to the fact that the ISpVoice::Speak() function requires that the first parameter be of type LPCWSTR, IOW a "const pointer to a wide character string". The following function may be of assistance to you.
inline std::wstring s2w(const std::string &s, const std::locale &loc = std::locale())
{
typedef std::ctype<wchar_t> wchar_facet;
std::wstring return_value;
if (s.empty())
{
return return_value;
}
if (std::has_facet<wchar_facet>(loc))
{
std::vector<wchar_t> to(s.size() + 2, 0);
std::vector<wchar_t>::pointer toPtr = &to[0];
const wchar_facet &facet = std::use_facet<wchar_facet>(loc);
if (0 != facet.widen(s.c_str(), s.c_str() + s.size(), toPtr))
{
return_value = to.data();
}
}
return return_value;
}
Then change the line of code to the following.
hr = pVoice->Speak(s2w(sTranslated).c_str(), 0, NULL);
The c_str() method returns a pointer to a "C-string equivalent" of the std::wstring object. IOW, it returns a pointer to a null-terminated wide string.

char to ACHAR + objectARX

I am trying to convert previous code to VS 2010. The code I am trying to convert is mentioned below. The function addCommand is defined like
addCommand(const ACHAR * cmdGroupName, const ACHAR * cmdGlobalName, const ACHAR * cmdLocalName, Adesk::Int32 commandFlags, AcRxFunctionPtr FunctionAddr,AcEdUIContext *UIContext=NULL, int fcode=-1, HINSTANCE hResourceHandle=NULL, AcEdCommand** cmdPtrRet=NULL)
The third required argument is of type ACHAR. The function is called in the following way.
char cmdLocRes[65];
// If idLocal is not -1, it's treated as an ID for
// a string stored in the resources.
if (idLocal != -1) {
// Load strings from the string table and register the command.
::LoadString(_hdllInstance, idLocal, cmdLocRes, 64);
acedRegCmds->addCommand(cmdGroup, cmdInt, cmdLocRes, cmdFlags, cmdProc);
My problem is that the variable cmdLocRes is of type char but the argument needs to be of type ACHAR.
How can I convert the same ?
ACHAR is a typedef (made by Autodesk in file AdAChar.h) of wchar_t. So the question is how to convert a char to wchar_t.
In a wider context this problem is because of the existence of unicode. Linux and Windows programmers normally discuss it without understanding each other. As I do not understand it, too, I cannot explain it. There are threads for the eager beaver: What's "wrong" with C++ wchar_t and wstrings? What are some alternatives to wide characters?
The folling might give you an idea how to convert it.
// Convert char to wchar_t
char cmdLocRes[65];
// Remark: Make sure cmdLocRes contains elements!
cmdLocRes[0] = 'A';
cmdLocRes[1] = '\0';
// Get a wstringstream
std::wstringstream str;
// Write the char array to the wstringstream
str << cmdLocRes;
// Get a wstring from the wstringstream
std::wstring wstr = str.str();
// Get a wchar_t from the wstring
const wchar_t *chr1 = wstr.c_str();
const ACHAR *chr2 = wstr.c_str(); // We see that wchar_t == ACHAR!
Better think of using wchar_t cmdLocRes[65] instead of char cmdLocRes[65]!
Sorry for the code style, but this text field is another great example for how not to do it. It took me longer to try to format the code block (and please look at it!!!) than to write the answer. Jesus!!!

conversion of Cstring to BYTE

I am using Visual Studio c++ and want to convert the Cstring to Byte. I have written this code but it gave me error in the second line that "data" is undefined.
CString data = _T( "OK");
LPBYTE pByte = new BYTE[data.GetLength() + 1];
memcpy(pByte, (VOID*)LPCTSTR(data), data.GetLength());
Further more I need to convert LPBYTE to const char for strcmp function. I have written the code but I can't find the issue with it.
const LPBYTE lpBuffer;
LPBYTE lpData = lpBuffer;
CString rcvValue(LPCSTR(lpBuffer));
const CHAR* cstr = (LPCSTR)rcvValue;
if (strcmp (cstr,("ABC")) == 0)
{
////
}
The CString type is a template specialization of CStringT, depending on the character set it uses (CStringA for ANSI, CStringW for Unicode). While you ensure to use a matching encoding when constructing from a string literal by using the _T macro, you fail to account for the different size requirements when copying the controlled sequence to the buffer.
The following code fixes the first part:
CString data = _T("OK");
size_t size_in_bytes = (data.GetLength() + 1) * sizeof(data::XCHAR);
std::vector<BYTE> buffer(size_in_bytes);
unsigned char const* first = static_cast<unsigned char*>(data.GetString());
unsigned char const* last = first + size_in_bytes;
std::copy(first, last, buffer.begin());
The second question is really asking to solve a solved problem. The CStringT type already provides a CStringT::Compare member, that can be used:
const LPBYTE lpBuffer;
CString rcvValue(static_cast<char const*>(lpBuffer));
if (rcvValue.Compare(_T("ABC")) == 0)
{
////
}
General advice: Always prefer using the concrete CStringT specialization matching your character encoding, i.e. CStringA or CStringW. The code will be much easier to read and reason about, and when you run into problems you need help with, you can post a question at Stack Overflow, without having to explain, what compiler settings you are using.
Make sure you include atlstr.h to provide the definition of CString, as below:
#include "stdafx.h"
#include <Windows.h>
#include <atlstr.h>
int _tmain(int argc, _TCHAR* argv[])
{
CString data = _T( "OK");
LPBYTE pByte = new BYTE[data.GetLength() + 1];
memcpy(pByte, (VOID*)LPCTSTR(data), data.GetLength());
return 0;
}
I'm fairly certain Jay is correct for your first question. You need to include the right header.
For your second question, why would you expect that code to work? Let's walk through what the code you've written actually does.
Create a char pointer (char *) without initializing it. This leaves lpData/lpBuffer pointing to a random location in memory.
Create a CString and initialize it with this random pointer.
Extract the buffer from the CString and compare it to a string literal.
Keeping in mind that the CString contains random garbage, what exactly do you expect this code to do? (Other than crash horribly? =) )
I also want to point out that you need to be more consistent in your approach to strings. Do you plan to support both char and wchar_t based strings as your use of TCHAR in the first sections suggests? Do you want to work with C-Style strings or do you want to use objects like CString? If you want to work with CString's, just use the Compare function that CString provides. Don't bother with strcmp.
Probably you didn't include the cruicial header
#include <afx.h>
int main()
{
CString data = _T( "OK");
LPBYTE pByte = new BYTE[data.GetLength() + 1];
memcpy(pByte, (VOID*)LPCTSTR(data), data.GetLength());
return 0;
}
This code works fine.
You should rather use
CString ss = "123ABC";
BYTE* bp = (BYTE*)ss.GetBuffer(ss.GetLength());
BYTE expected[16] ;
CopyMemory(expected,bp,sizeof(expected));
Just using '=' won't work.

Conversion of ATL CString to character array

I want to convert a CString into a char[]. Some body tell me how to do this?
My code is like this :
CString strCamIP1 = _T("");
char g_acCameraip[16][17];
strCamIP1 = theApp.GetProfileString(strSection, _T("IP1"), NULL);
g_acCameraip[0] = strCamIP1;
This seems to be along the right lines; http://msdn.microsoft.com/en-us/library/awkwbzyc.aspx
CString aCString = "A string";
char myString[256];
strcpy(myString, (LPCTSTR)aString);
which in your case would be along the lines of
strcpy(g_acCameraip[0], (LPCTSTR)strCamIP1);
From MSDN site:
// Convert to a char* string from CStringA string
// and display the result.
CStringA origa("Hello, World!");
const size_t newsizea = (origa.GetLength() + 1);
char *nstringa = new char[newsizea];
strcpy_s(nstringa, newsizea, origa);
cout << nstringa << " (char *)" << endl;
CString is based on TCHAR so if don't compile with _UNICODE it's CStringA or if you do compile with _UNICODE then it is CStringW.
In case of CStringW conversion looks little bit different (example also from MSDN):
// Convert to a char* string from a wide character
// CStringW string. To be safe, we allocate two bytes for each
// character in the original string, including the terminating
// null.
const size_t newsizew = (origw.GetLength() + 1)*2;
char *nstringw = new char[newsizew];
size_t convertedCharsw = 0;
wcstombs_s(&convertedCharsw, nstringw, newsizew, origw, _TRUNCATE );
cout << nstringw << " (char *)" << endl;
You could use wcstombs_s:
// Convert CString to Char By Quintin Immelman.
//
CString DummyString;
// Size Can be anything, just adjust the 100 to suit.
const size_t StringSize = 100;
// The number of characters in the string can be
// less than String Size. Null terminating character added at end.
size_t CharactersConverted = 0;
char DummyToChar[StringSize];
wcstombs_s(&CharactersConverted, DummyToChar,
DummyString.GetLength()+1, DummyString,
_TRUNCATE);
//Always Enter the length as 1 greater else
//the last character is Truncated
If you are using ATL you could use one of the conversion macros. CString stores data as tchar, so you would use CT2A() (C in macro name stands for const):
CString from("text");
char* pStr = CT2A((LPCTSTR)from);
Those macros are smart, if tchar represents ascii (no _UNICODE defined), they just pass the pointer over and do nothing.
More info below, under ATL String-Conversion Classes section:
http://www.369o.com/data/books/atl/index.html?page=0321159624%2Fch05.html
CStringA/W is cheaply and implicitly convertible to const char/wchar_t *. Whenever you need C-style string, just pass CString object itself (or the result of .GetString() which is the same). The pointer will stay valid as long as string object is alive and unmodified.
strcpy(g_acCameraip[0], strCamIP1);
// OR
strcpy(g_acCameraip[0], strCamIP1.GetString());
If you need writable (non-const) buffer, use .GetBuffer() with optional maximum length argument.
If you have CStringW but you need const char* and vice versa, you can use a temporary CStringA object:
strcpy(g_acCameraip[0], CStringA(strCamIP1).GetString());
But a much better way would be to have array of CStrings. You can use them whereever you need null-terminated string, but they will also manage string's memory for you.
std::vector<CString> g_acCameraip(16);
g_acCameraip[0] = theApp.GetProfileString(strSection, _T("IP1"), NULL);
Use memcpy .
char c [25];
Cstring cstr = "123";
memcpy(c,cstr,cstr.GetLength());
Do you really have to copy the CString objects into fixed char arrays?
enum { COUNT=16 };
CString Cameraip[COUNT];
Cameraip[0] = theApp.GetProfileString(strSection, _T("IP1"), NULL);
// add more entries...
...and then - later - when accessing the entries, for example like this
for (int i=0; i<COUNT; ++i) {
someOp(Cameraip[i]); // the someOp function takes const CString&
}
...you may convert them, if needed.
fopen is the function which needs char* param. so if you have CString as available string, you can just use bellow code.
be happy :)
Here, cFDlg.GetPathName().GetString(); basically returns CString in my code.
char*pp = (char*)cFDlg.GetPathName().GetString();
FILE *fp = ::fopen(pp,"w");
CString str;
//Do something
char* pGTA = (LPTSTR)(LPCTSTR)str;//Now the cast
Just (LPTSTR)(LPCTSTR). Hope this is what you need :)
char strPass[256];
strcpy_s( strPass, CStringA(strCommand).GetString() );
It's simple
ATL CStrings allow very simple usage without having to do a lot of conversions between types. You can most easily do:
CString cs = "Test";
const char* str = static_cast<LPCTSTR>(cs);
or in UNICODE environment:
CString cs = "Test";
const wchar_t* str = static_cast<LPCTSTR>(cs);
How it works
The static_cast (or alternatively C-Style cast) will trigger the CString::operator LPCTSTR, so you don't do any pointer reinterpretation yourself but rely on ATL code!
The documentation of this cast operator says:
This useful casting operator provides an efficient method to access the null-terminated C string contained in a CString object. No characters are copied; only a pointer is returned. Be careful with this operator. If you change a CString object after you have obtained the character pointer, you may cause a reallocation of memory that invalidates the pointer.
Modifiable Pointers
As mentioned in the above statement, the returned pointer by the cast operator is not meant to be modified. However, if you still need to use a modifiable pointer for some outdated C libraries, you can use a const_cast (if you are sure that function wont modify the pointer):
void Func(char* str) // or wchar_t* in Unicode environment
{
// your code here
}
// In your calling code:
CString cs = "Test";
Func(const_cast<LPTSTR>(static_cast<LPCTSTR>(test))); // Call your function with a modifiable pointer
If you wish to modify the pointer, you wont get around doing some kind of memory copying to modifiable memory, as mentioned by other answers.
There is a hardcoded method..
CString a = L"This is CString!";
char *dest = (char *)malloc(a.GetLength() + 1);
// +1 because of NULL char
dest[a.GetLength()] = 0; // setting null char
char *q = (char *)a.m_pszData;
//Here we cannot access the private member..
//The address of "m_pszData" private member is stored in first DWORD of &a...
//Therefore..
int address = *((int *)&a);
char *q = (char *)address;
// Now we can access the private data!, This is the real magic of C
// Size of CString's characters is 16bit...
// in cstring '1' will be stored as 0x31 0x00 (Hex)
// Here we just want even indexed chars..
for(int i = 0;i<(a.GetLength()*2);i += 2)
dest[i/2] = *(q+i);
// Now we can use it..
printf("%s", dest);

converting narrow string to wide string

How can i convert a narrow string to a wide string ?
I have tried this method :
string myName;
getline( cin , myName );
wstring printerName( L(myName) ); // error C3861: 'L': identifier not found
wchar_t* WprinterName = printerName.c_str(); // error C2440: 'initializing' : cannot convert from 'const wchar_t *' to 'wchar_t *'
But i get errors as listed above.
Why do i get these errors ? How can i fix them ?
Is there any other method of directly converting a narrow string to a wide string ?
If the source is ASCII encoded, you can just do this:
wstring printerName;
printerName.assign( myName.begin(), myName.end() );
You should do this :
inline std::wstring convert( const std::string& as )
{
// deal with trivial case of empty string
if( as.empty() ) return std::wstring();
// determine required length of new string
size_t reqLength = ::MultiByteToWideChar( CP_UTF8, 0, as.c_str(), (int)as.length(), 0, 0 );
// construct new string of required length
std::wstring ret( reqLength, L'\0' );
// convert old string to new string
::MultiByteToWideChar( CP_UTF8, 0, as.c_str(), (int)as.length(), &ret[0], (int)ret.length() );
// return new string ( compiler should optimize this away )
return ret;
}
This expects the std::string to be UTF-8 (CP_UTF8), when you have another encoding replace the codepage.
Another way could be :
inline std::wstring convert( const std::string& as )
{
wchar_t* buf = new wchar_t[as.size() * 2 + 2];
swprintf( buf, L"%S", as.c_str() );
std::wstring rval = buf;
delete[] buf;
return rval;
}
I found this while googling the problem. I have pasted the code for reference. Author of this post is Paul McKenzie.
std::string str = "Hello";
std::wstring str2(str.length(), L' '); // Make room for characters
// Copy string to wstring.
std::copy(str.begin(), str.end(), str2.begin());
ATL (non-express editions of Visual Studio) has a couple useful class types which can convert the strings plainly. You can use the constructor directly, if you do not need to hold onto the string.
#include <atlbase.h>
std::wstring wideString(L"My wide string");
std::string narrowString("My not-so-wide string");
ATL::CW2A narrow(wideString.c_str()); // narrow is a narrow string
ATL::CA2W wide(asciiString.c_str()); // wide is a wide string
Here are two functions that can be used: mbstowcs_s and wcstombs_s.
mbstowcs_s: Converts a sequence of multibyte characters to a corresponding sequence of wide characters.
wcstombs_s: Converts a sequence of wide characters to a corresponding sequence of multibyte characters.
errno_t wcstombs_s(
size_t *pReturnValue,
char *mbstr,
size_t sizeInBytes,
const wchar_t *wcstr,
size_t count
);
errno_t mbstowcs_s(
size_t *pReturnValue,
wchar_t *wcstr,
size_t sizeInWords,
const char *mbstr,
size_t count
);
See http://msdn.microsoft.com/en-us/library/eyktyxsx.aspx and http://msdn.microsoft.com/en-us/library/s7wzt4be.aspx.
The Windows API provides routines for doing this: WideCharToMultiByte() and MultiByteToWideChar(). However, they are a pain to use. Each conversion requires two calls to the routines and you have to look after allocating/freeing memory and making sure the strings are correctly terminated. You need a wrapper!
I have a convenient C++ wrapper on my blog, here, which you are welcome to use.
The original question of this thread was: "How can i convert a narrow string to a wide string?"
However, from the example code given in the question, there seems to be no conversion necessary. Rather, there is a compiler error due to the newer compilers deprecating something that used to be okay. Here is what I think is going on:
// wchar_t* wstr = L"A wide string"; // Error: cannot convert from 'const wchar_t *' to 'wchar_t *'
wchar_t const* wstr = L"A wide string"; // okay
const wchar_t* wstr_equivalent = L"A wide string"; // also okay
The c_str() seems to be treated the same as a literal, and is considered a constant (const). You could use a cast. But preferable is to add const.
The best answer I have seen for converting between wide and narrow strings is to use std::wstringstream. And this is one of the answers given to C++ Convert string (or char*) to wstring (or wchar_t*)
You can convert most anything to and from strings and wide strings using stringstream and wstringstream.
This article published on the MSDN Magazine 2016 September issue discusses the conversion in details using Win32 APIs.
Note that using MultiByteToWideChar() is much faster than using the std:: stuff on Windows.
Use mbtowc():
string myName;
wchar_t wstr[BUFFER_SIZE];
getline( cin , myName );
mbtowc(wstr, myName, BUFFER_SIZE);