8

This question may already be having an answer but I felt I needed to ask it because I cant seem to get the answer I need for the code to work as intended on VS Community 2017 since it worked well on VS Express Edition.

I am trying to implement a code i picked up from a c project but I can't see how to get around the error:

Value of type "const char *" cannot be assigned to an entity of type "LPSTR"

and

cannot convert from 'const char [7]' to 'LPSTR'

    MENUITEMINFO mii = { 0 };

    mii.cbSize = sizeof(MENUITEMINFO);
    mii.fMask = MIIM_TYPE;
    mii.fType = MFT_STRING;
    mii.dwTypeData = _T("item 1"); // error is on this line
    mii.dwTypeData = _T("item 2"); // error is on this line also

NOTE:

  1. This is c code now on c++ project. It worked in VS Express Edition but cant compile on VS Community 2017
  2. VS Express Edition I simply changed Character set to Multi byte and it worked but on VS Community 2017 nothing seems to work and I can't see how to fix the code itself
Jack Siro
  • 677
  • 10
  • 29

2 Answers2

10

A string literal is of type const char[N], its contents must not be modified. The ability to implicitly convert string literals to char* was only ever there in C++ for backwards compatibility with C. It's a very dangerous thing, has been deprecated basically forever, and was finally removed in C++11. Visual Studio 2017 switched the default language standard to C++14, which is most likely the reason why your code stopped working there. If you absolutely, positively, definitely know for sure that the string pointed to won't be modified, then you can use a const_cast

MENUITEMINFO mii = { 0 };

mii.cbSize = sizeof(MENUITEMINFO);
mii.fMask = MIIM_TYPE;
mii.fType = MFT_STRING;
mii.dwTypeData = const_cast<char*>("item 1");

Ideally, you would just use const char*, but interop with some old C APIs, unfortunately, sometimes requires the use of const_cast. Before you do this sort of thing, always check the API documentation to make sure that there is no way the API will attempt to modify the contents of the string.

In the case of your MENUITEMINFO here, the reason why the dwTypeData is a char* rather than a const char* is most likely that the struct is intended to be used with both GetMenuItemInfo and SetMenuItemInfo where the former expects a pointer to a buffer in which it will write a string while the latter expects a pointer to a buffer from which it will read a string…

Michael Kenzel
  • 15,508
  • 2
  • 30
  • 39
  • thanks fixed the issue and with character set to multi bite it works – Jack Siro Apr 02 '19 at 11:53
  • You should use `MAKEINTRESOURCE("item 1");` instead of type casting. – 273K Apr 02 '19 at 11:59
  • 3
    @S.M. I don't see resources being used here anywhere, so I'm not sure what you think should be achieved by `MAKEINTRESOURCE`. Apart from that, while using `MAKEINTRESOURCE` on a string literal unfortunately compiles because the macro happens to be using a ton of C-style casts iternally, it's completely wrong. Do not do that. – Michael Kenzel Apr 02 '19 at 12:08
  • 1
    @JackSiro I would actually recommend to just use either the ANSI (the names ending with A) or Unicode (names ending with W) variants of the Windows APIs explicitly. The main purpose of all the switches and macros related to string types was to aid in maintaining code that was supposed to be compiled to use either ANSI oder Unicode. Windows is all Unicode internally by now, the ANSI APIs are really just wrappers that convert the string and forward to the Unicode APIs. Nowadays, I'd just use the Unicode APIs. The Multibyte setting in particular is most likely not what you think it is… – Michael Kenzel Apr 02 '19 at 12:29
  • If you don't see any resource being used there it does not mean your answer is correct. Look at https://stackoverflow.com/questions/3610565/why-does-makeintresource-work to discover gups in your experience. – 273K Apr 02 '19 at 17:18
  • @S.M. I don't see `MENUITEMINFO` or anything else relating to the question here mentioned in the thread you linked to. The question here was about a specific error encountered when trying to use a string literal with `dwTypeData` in a `MENUITEMINFO`. Could you please elaborate why `MAKEINTRESOURCE` would be needed to do so and why you think my answer is incorrect!? – Michael Kenzel Apr 02 '19 at 17:26
  • Absolute values of pointers less than 64KB are treated as resource identifiers, greater values are treated as pointers to string values. Thus you can pass to there a resource identifier or a string literal using only `MAKEINTRESOURCE` macro in both cases. Sorry, I didn't want to say that you answer is incorrect, it is rather not completely right. – 273K Apr 03 '19 at 03:13
1

LPSTR is char *. You shouldn't convert from const char * to char *, even if there are methods when it's possible.

Just allocate space, then use strcpy/memcpy to copy the value.

Or, since you're playing with MENUITEMINFO, use one of the specific functions that handle menu items(like SetMenuItemInfoA)

Shlomi Agiv
  • 1,183
  • 7
  • 17