Formating a string using sprintf and showing it in MessageBox!

B

babak

Hi everyone
I want to format a string (using sprintf) and put it in a messagebox
but however I try to do it, it doesn't seem to work.
Here is an example sample of what i try to do:

char msg[120];
string my_name = "John";

sprintf (msg, "My name is: %s ", my_name);
MessageBox(NULL, msg, NULL, MB_OK);


And this is the error I get:

error C2664: 'MessageBoxW' : cannot convert parameter 2 from 'char
[120]' to 'const unsigned short *'
Types pointed to are unrelated; conversion requires reinterpret_cast,
C-style cast or function-style cast

I know that MessageBox wants a LPCTSTR as its second parameter. If I
use that instead (see below)...

LPCTSTR msg;
string my_name = "John";

sprintf (msg, "My name is: %s ", my_name);
MessageBox(NULL, msg, NULL, MB_OK);


....I get the following error:

error C2664: 'sprintf' : cannot convert parameter 1 from 'const
unsigned short *' to 'char *'
Types pointed to are unrelated; conversion requires reinterpret_cast,
C-style cast or function-style cast

Seems like what ever I try to use either sprintf or MessageBox is not
happy. If I try to cast 'msg' in either sprintf or MessageBox I just
get junk as my output.
Does anyone have a suggestion how I can solve this? Please note that I
don't want to use CString since my platform does not seem to support
that. An example code of how I can solve this problem would be much
appreciated.

Thanks a lot for your help.
/Babak
 
J

Jochen Kalmbach [MVP]

Hi babak!
I want to format a string (using sprintf) and put it in a messagebox
but however I try to do it, it doesn't seem to work.
Here is an example sample of what i try to do:

char msg[120];
string my_name = "John";

sprintf (msg, "My name is: %s ", my_name);
MessageBox(NULL, msg, NULL, MB_OK);


And this is the error I get:

error C2664: 'MessageBoxW' : cannot convert parameter 2 from 'char
[120]' to 'const unsigned short *'

You compile a UNICODE program but you heare are dealing with ANSI strings...

Change it to

<code>
ifdef _UNICODE
#define tstring std::wstring
#else
#define tstring std::string
#endif

TCHAR msg[120];
tstring my_name = _T("John");
__stprintf(msg, _T("My name is: %s "), (LPCTSTR) my_name);
MessageBox(NULL, msg, NULL, MB_OK);
</code>

--
Greetings
Jochen

My blog about Win32 and .NET
http://blog.kalmbachnet.de/
 
M

Mihai N.

error C2664: 'MessageBoxW' : cannot convert parameter 2 from 'char
[120]' to 'const unsigned short *'
Types pointed to are unrelated; conversion requires reinterpret_cast,
C-style cast or function-style cast
Looks like the applicaiton is Unicode.
LPCTSTR msg;
string my_name = "John";

sprintf (msg, "My name is: %s ", my_name);
MessageBox(NULL, msg, NULL, MB_OK);
What is "string" ?
Anyway, try:

TCHAR msg[120];
TCHAR *my_name = _T("John");

_stprintf (msg, _T("My name is: %s "), my_name);
MessageBox(NULL, msg, NULL, MB_OK);

Notes:
----------------
LPCTSTR msg;
will crash you application, because it is a non-initialized pointer.
It expands to
LPCTSTR:
LP = Long Pointer (the long is obsolete, from the old days when
Intel procesors used segmented memory)
C = const
T = generic text type
STR = string
So, this becomes:
if Non-Unicode: const char * msg;
if Unicode: const wchar_t * msg;
Generic: const TCHAR * msg;
----------------
Note _stprintf insted of sprintf and _T(".....")
If you read the doc for sprintf, you will see a table named
"Generic-Text Routine Mappings". "TCHAR.H routine" is what you
allways want.
----------------
Read about the the "Generic-Text Routine Mappings" in MSDN.
----------------
Read this blurb: http://www.mihainita.net/20050306b.shtml
Please note that I don't want to use CString since my platform does not
seem to support that.
CString is part of MFC (MFC/ATL in VC.NET). If you configure the
project to use MFC, then you will get it.
 
M

Mihai N.

ifdef _UNICODE
#define tstring std::wstring
#else
#define tstring std::string
#endif

TCHAR msg[120];
tstring my_name = _T("John");
__stprintf(msg, _T("My name is: %s "), (LPCTSTR) my_name);
MessageBox(NULL, msg, NULL, MB_OK);
</code>


I did not think about std::string :)
Jochen is right, that is what you should do.

But he is not right in double-underscore in __stprintf :)
Correct that, and you have a running thing.
 
B

babak

Hi Jochen
Thanks for your help. I tried what you suggested and got the following
error:

error C2440: 'type cast' : cannot convert from 'class
std::basic_string<unsigned short,struct std::char_traits<unsigned
short>,class std::allocator<unsigned short> >' to 'const unsigned short
*'
No user-defined-conversion operator available that can perform this
conversion, or the operator cannot be called

This doesn't seem like the right approach to me because to my
understanding the variable that the compiler is not happy with is 'msg'
(i.e the first parameter in sprintf and second parameter in MessageBox)
and not 'string' (which you refer to as 'tstring' in your code) that
you changed in your code. Have I missunderstood this totally?

/Babak
 
J

Jochen Kalmbach [MVP]

Hi Mihai!
But he is not right in double-underscore in __stprintf :)
Correct that, and you have a running thing.

Upps... it was a copy-and-past error...

But to be even better, he should use "_sntprintf" instead of "_stprintf"!

<code>
ifdef _UNICODE
#define tstring std::wstring
#else
#define tstring std::string
#endif

TCHAR msg[120];
tstring my_name = _T("John");
_sntprintf(msg, 120, _T("My name is: %s "), (LPCTSTR) my_name);
MessageBox(NULL, msg, NULL, MB_OK);
</code>


--
Greetings
Jochen

My blog about Win32 and .NET
http://blog.kalmbachnet.de/
 
B

babak

Thanks for explanations in the notes to your first message, Mihai. It
is all now a little bit more clear to me. However, as I wrote in my
last message, this still does not seem to work (I used single
underscore in _sprintf). Any suggestions?

Thanks for your help.
/Babak
 
J

Jochen Kalmbach [MVP]

Hi babak!
error C2440: 'type cast' : cannot convert from 'class
std::basic_string<unsigned short,struct std::char_traits<unsigned
short>,class std::allocator<unsigned short> >' to 'const unsigned short
*'
No user-defined-conversion operator available that can perform this
conversion, or the operator cannot be called

Upps.. I forgot that the STL-(w)string class has not const-operator...

Here is a complete working example:

#include <windows.h>
#include <tchar.h>
#include <stdio.h>
#pragma comment(lib, "user32.lib")

#include <string>

#ifdef _UNICODE
#define tstring std::wstring
#else
#define tstring std::string
#endif

int _tmain()
{
TCHAR msg[120];
tstring my_name = _T("John");
_sntprintf(msg, 120, _T("My name is: %s "), my_name.c_str());
MessageBox(NULL, msg, NULL, MB_OK);
}

--
Greetings
Jochen

My blog about Win32 and .NET
http://blog.kalmbachnet.de/
 
J

Jochen Kalmbach [MVP]

Here is a complete working example:
Again a really, really complete working example:

#include <windows.h>
#include <tchar.h>
#include <stdio.h>
#pragma comment(lib, "user32.lib")

#include <string>

#ifdef _UNICODE
#define tstring std::wstring
#else
#define tstring std::string
#endif

int _tmain()
{
TCHAR msg[120+1];
tstring my_name = _T("John");
_sntprintf(msg, 120, _T("My name is: %s "), my_name.c_str());
msg[120] = 0;
MessageBox(NULL, msg, NULL, MB_OK);
}

--
Greetings
Jochen

My blog about Win32 and .NET
http://blog.kalmbachnet.de/
 
B

babak

Thanks a lot for your help. Not it seems to be working properly!

/Babak

Mihai N. skrev:
error C2664: 'MessageBoxW' : cannot convert parameter 2 from 'char
[120]' to 'const unsigned short *'
Types pointed to are unrelated; conversion requires reinterpret_cast,
C-style cast or function-style cast
Looks like the applicaiton is Unicode.
LPCTSTR msg;
string my_name = "John";

sprintf (msg, "My name is: %s ", my_name);
MessageBox(NULL, msg, NULL, MB_OK);
What is "string" ?
Anyway, try:

TCHAR msg[120];
TCHAR *my_name = _T("John");

_stprintf (msg, _T("My name is: %s "), my_name);
MessageBox(NULL, msg, NULL, MB_OK);

Notes:
----------------
LPCTSTR msg;
will crash you application, because it is a non-initialized pointer.
It expands to
LPCTSTR:
LP = Long Pointer (the long is obsolete, from the old days when
Intel procesors used segmented memory)
C = const
T = generic text type
STR = string
So, this becomes:
if Non-Unicode: const char * msg;
if Unicode: const wchar_t * msg;
Generic: const TCHAR * msg;
----------------
Note _stprintf insted of sprintf and _T(".....")
If you read the doc for sprintf, you will see a table named
"Generic-Text Routine Mappings". "TCHAR.H routine" is what you
allways want.
----------------
Read about the the "Generic-Text Routine Mappings" in MSDN.
----------------
Read this blurb: http://www.mihainita.net/20050306b.shtml
Please note that I don't want to use CString since my platform does not
seem to support that.
CString is part of MFC (MFC/ATL in VC.NET). If you configure the
project to use MFC, then you will get it.
 
M

Mihai N.

But to be even better, he should use "_sntprintf" instead of "_stprintf"!
....
TCHAR msg[120];
tstring my_name = _T("John");
_sntprintf(msg, 120, _T("My name is: %s "), (LPCTSTR) my_name);

True. What I normaly do is this:

#define DIM(a) (sizeof(a)/sizeof(a[0]))
_sntprintf( msg, DIM(msg), ... );

This way you don't have to manualy keep in sync the
_sntprintf parameter with the buffer size.
You just have to be careful to use it only on pointers,
not on arrays.
I also have something in C++, using templates, that gives
compile error if used on pointers.
But is a bit long to post here. And VC2005 will have something anyway :)
 
J

Jochen Kalmbach [MVP]

Hi Mihai!
But to be even better, he should use "_sntprintf" instead of "_stprintf"!
TCHAR msg[120];
tstring my_name = _T("John");
_sntprintf(msg, 120, _T("My name is: %s "), (LPCTSTR) my_name);

True. What I normaly do is this:

#define DIM(a) (sizeof(a)/sizeof(a[0]))
_sntprintf( msg, DIM(msg), ... );

But this is wrong... (as I also did in my first most... ;-) )

If the resulting string is exactly the size of the passed buffer, then
*no* NUl characater will be appended...

So you need to do:
#define DIM(a) (sizeof(a)/sizeof(a[0]))
_snprintf(msg, DIM(msg)-1, ...);
msg[DIM(msg)-1] = 0;

--
Greetings
Jochen

My blog about Win32 and .NET
http://blog.kalmbachnet.de/
 
M

Mihai N.

So you need to do:
#define DIM(a) (sizeof(a)/sizeof(a[0]))
_snprintf(msg, DIM(msg)-1, ...);
msg[DIM(msg)-1] = 0;

In fact, if you do msg[DIM(msg)-1] = 0;
you can do _snprintf(msg, DIM(msg), ...); without problem.
It is just about "what's your style."

Ok, now we move from internationalization to security.
I know, snprintf is unsafe. You should use the safe string API from MS.

But I kust did not feel like taking any piece of code from newsgroups and
rising it to production code level.
This is what I do with my production code, true.
But on newsgroups, sometimes I do feel like baby-sitting, sometimes not.

For instance, I would not start here a discution about portability.
Not today. Some other day, maybe :)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top