Reputation: 12227
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
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
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
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
Reputation: 7542
MessageBox
does not have an overload taking a resource ID but you can use AfxMessageBox
instead.
Upvotes: 1