1

I created a basic Windows C++ application in Visual Studio 2015 and I have a few errors:

Erorrs image

#include <windows.h>
#include <stdlib.h>
#include <string.h>
#include <tchar.h>

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
    MessageBox(NULL, "Test_text", "Message Test", MB_ICONINFORMATION | MB_OKCANCEL);
    return 0;
}

Errors:

'int MessageBoxW(HWND,LPCWSTR,LPCWSTR,UNIT)': cannot convert argument 2 from 
'const char [10]' to 'LPCWSTR'

argument of type "const char *" is incompatible with parameter of type "LPCWSTR"
argument of type "const char *" is incompatible with parameter of type "LPCWSTR"
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
Vento
  • 37
  • 3
  • 9
  • 4
    Don't show errors or code via images (inline or externally linked). Always show the full text of the error here as text. – crashmstr Mar 01 '16 at 15:46
  • 1
    And if you'd search for the message text, you would have found the solution already. – MSalters Mar 01 '16 at 15:49

5 Answers5

5

You choose to use ANSI text, so you should use MessageBoxA explicitly instead of macro MessageBox.

#include <windows.h>
#include <stdlib.h>
#include <string.h>
#include <tchar.h>

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
    MessageBoxA(NULL, "Test_text", "Message Test", MB_ICONINFORMATION | MB_OKCANCEL);
    return 0;
}

Alternatively, you may useTEXT macro to have the compiler automatically match type of strings and functions.

#include <windows.h>
#include <stdlib.h>
#include <string.h>
#include <tchar.h>

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
    MessageBox(NULL, TEXT("Test_text"), TEXT("Message Test"), MB_ICONINFORMATION | MB_OKCANCEL);
    return 0;
}
MikeCAT
  • 73,922
  • 11
  • 45
  • 70
5

The problem here is the Win32 TCHAR model.

There's actually no MessageBox function: MessageBox is a preprocessor #define, that expands to MessageBoxA or MessageBoxW, based on your project settings (ANSI/MBCS or Unicode, respectively).

Starting with VS2005, the default setting in Visual Studio has been Unicode (to be more precise: UTF-16). So the MessageBoxW API (i.e. the Unicode version) is picked in this case by the compiler.

The MessageBoxW API takes Unicode (UTF-16) strings, represented via wchar_t pointers (the obscure LPCWSTR preprocessor macro is expanded to const wchar_t*, i.e. a NUL-terminated C-style Unicode UTF-16 string).

Unicode (UTF-16) string literals are represented using the L"..." syntax (note the L prefix).
So, while "Test_text" is an ANSI string literal, L"Test_text" is a Unicode (UTF-16) string literal.

Since your are (implicitly, via Visual Studio default settings) doing a Unicode build, you should decorate your string literals with the L prefix, e.g.:

MessageBox(nullptr,   // <--- prefer nullptr to NULL in modern C++ code 
           L"Test_text",      // <--- Unicode (UTF-16) string literal 
           L"Message Test",   // <--- Unicode (UTF-16) string literal
           MB_ICONINFORMATION | MB_OKCANCEL);

An alternative is to decorate the string literals using the _T("...") or TEXT("...") macros. These will be expanded to simple "..." ANSI string literals in ANSI/MBCS builds, and to Unicode (UTF-16) string literals L"..." in Unicode builds (which are the default in modern versions of Visual Studio).

// TEXT("...") works in both ANSI/MBCS and Unicode builds
MessageBox(nullptr, 
           TEXT("Test_text"),    
           TEXT("Message Test"),
           MB_ICONINFORMATION | MB_OKCANCEL);

Personally, I consider the TCHAR model an obsolete model from the past (I see no reason to produce ANSI builds of modern C++ Win32 applications), and considering that modern Windows APIs are Unicode-only (e.g. DrawThemeText()), I'd just decorate strings literals using the L"..." prefix, and kind of forget about the ANSI builds.

Mr.C64
  • 41,637
  • 14
  • 86
  • 162
  • When passing wide character string literals, you should explicitly call the wide character version of the API (i.e. `MessageBoxW` instead of `MessageBox`). – IInspectable Mar 02 '16 at 14:06
  • @IInspectable: I don't agree. `MessageBoxW` (or `DoSomethingW` in general) is an useless _code uglification_ in Unicode builds: the ending `W` is just noise over the clearer `MessageBox` (or `DoSomething`) form. – Mr.C64 Mar 02 '16 at 17:17
  • This is not about opinions, it's about language rules. `MessageBox` is the generic text mapping version. `MessageBoxW` is the Unicode version. I would take what you believe to be *"uglification"* over relying on an environment outside my control any day. – IInspectable Mar 02 '16 at 18:00
  • I understand your reasoning about `MessageBox` being a mapping, but if my code doesn't need to be built in ANSI mode, I prefer `MessageBox` with `L"..."`, which has the positive side-effect of breaking compilation if someone tries to do an ANSI build (instead of UNICODE build). – Mr.C64 Mar 02 '16 at 20:42
  • There's nothing positive about breaking code due to incompatible formal parameters and arguments passed to a function. It's worse, still: If you aren't explicit about the function you wish to call, you might not be calling the function you intended to call altogether. When passing `nullptr` the compiler won't help you. It'll just let you accidentally call a function you never meant to call. Using the preprocessor symbols for the generic text mappings instead of the real function names doesn't have a single advantage going for it. Stop proposing it based on false claims. – IInspectable Mar 03 '16 at 12:38
  • @IInspectable: I don't get what you mean about passing `nullptr`. I'm talking about string literals. As I said, I see no problems in using the more readable `DoSomething` API instead of the more noisy `DoSomethingW` in Unicode builds, with `L"..."` string literals (to be honest, I prefer loading string from resources for better localization, so there aren't much literals). This is my position, yours may be different. Enough for me (this is starting to sound like where to put braces or how much indenting code). – Mr.C64 Mar 03 '16 at 17:31
4

MessageBox in this case is actually MessageBoxW, it takes unicode strings. You can fix it in this way:

MessageBoxW(NULL, L"Test_text", L"Message Test", MB_ICONINFORMATION | MB_OKCANCEL);

or

MessageBox(NULL, TEXT("Test_text"), TEXT("Message Test"), MB_ICONINFORMATION | MB_OKCANCEL);
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
CodeFuller
  • 30,317
  • 3
  • 63
  • 79
2

You can't pass a bare string literal like that.

MessageBox(NULL, TEXT("Test_text"), TEXT("Message Test"), MB_ICONINFORMATION | MB_OKCANCEL);

TEXT is a macro that expands to the right string type depending the way you compile.

Daniel A. White
  • 187,200
  • 47
  • 362
  • 445
  • `_T` is for use with CRT and `TEXT` is for use with Windows API, so using `TEXT` is better in this case. – MikeCAT Mar 01 '16 at 15:34
0

You need to choose the correct setting for the Character Set for your project. In the properties of your Visual Studio Project, navigate to the General category. In there is an entry Character Set.

If you choose Unicode Character Set the compiler will define _UNICODE for you and all functions like MessageBox will evaluate to their wide-character variant, like MessageBoxW.

If you choose Multi-Byte (deprecated) the compiler will define _MBCS for you and the functions will evaluate to the multi-byte variants, like MessageBoxA.

The same comes in for strings, the macros mentioned in the answers (like TEXT) will add an L in front of all your strings in a unicode environment.

See here for more information: https://msdn.microsoft.com/en-us/library/ey142t48.aspx

IMHO there are very few reasons where one wants to write explicitly against the W or A methods. If you have to do that to make your compiler happy, you should recheck your settings.

erg
  • 1,632
  • 1
  • 11
  • 23