zar
zar

Reputation: 12227

Why do I need this CString type cast?

I have moved my strings to resources and luckily I have LPCTSTR operator to instantiate strings conveniently like:

CString str( (LPCTSTR) IDS_MY_STRING);

Now I want to do similar type casting with MessageBox() so it loads the strings from resources as well so I go about like this:

MessageBox( hWnd, (LPCTSTR) IDS_MY_STRING , _T("Error"), MB_RETRYCANCEL);

But this doesn't work, it compiles but crashes at run time. Now the following does work:

MessageBox( hWnd, (CString) (LPCTSTR) IDS_MY_STRING , _T("Error"), MB_RETRYCANCEL);

My question is that MessageBox() takes LPCTSTR as 2nd parameter anyways so why do we have to typecast additionally from LPCTSTR to CString to make this work?

Upvotes: 2

Views: 1329

Answers (4)

Jerry Coffin
Jerry Coffin

Reputation: 490238

The real question (or at least the interesting part of the answer) is less about how the second fails, and more about how the first works.

The first works because CString's constructor that takes an LPCTSTR actually looks at the value to figure out whether it's really a pointer to a string, or the identifier of a string resource. In the latter case, it automatically loads the string resource and creates a CString with the same content. IOW, you're getting an implicit conversion from string identifier to CString.

CString also supports an implicit conversion to LPCTSTR/LPCSTR/LPCWSTR.

C++, however, will only do one user-defined implicit conversion to get from whatever type is passed to whatever type is needed for an expression. In this case, to get from a string ID to a LPCTSTR, you'd need two -- one from string ID to CString, and another from CString to LPCTSTR. The compiler won't do that for you automatically.

Therefore, to get from a string ID to an LPCTSTR, you need to explicitly convert from string ID to CString, which uses CString's constructor that takes an LPCTSTR. Therefore, you cast your string ID to LPCTSTR, and from that to CString, which creates a CString. Then the compiler will automatically convert from CString to a (real) LPCTSTR for you.

Upvotes: 5

user1149224
user1149224

Reputation:

Others have explained the details of type casts, etc.

Moreover, to simplify your code, you may want to #define a convenient macro like this:

#define _S(id) (CString(LPCTSTR(id))) 

and then use it with MessageBox (or for other LPCTSTR parameters as well):

MessageBox( hWnd, _S(IDS_MY_STRING), _S(IDS_TITLE), MB_RETRYCANCEL );

Upvotes: 2

Rob Kennedy
Rob Kennedy

Reputation: 163297

Your IDS_MY_STRING isn't really a pointer to a string. It's an integer. (If it were a string pointer, you'd never need the LPCTSTR cast in the first place.) CString knows how to load resource strings from integral resource IDs.

MessageBox doesn't; it requires a real character pointer, which CString provides implicitly.

Upvotes: 4

Christian Ammer
Christian Ammer

Reputation: 7542

MessageBox does not have an overload taking a resource ID but you can use AfxMessageBox instead.

Upvotes: 1

Related Questions