Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to initialize LPWSTR from a const string?

I am trying to initialize MENUITEMINFO for a call to InsertMenuItem. When trying to assign a const string to dwTypeData, I get an error. The code below is from MSDN samples.

I get an error for both types of assignment

mii.dwTypeData = "&Sample text";
mii.dwTypeData = L"&Sample text";

I am using Visual Studio 2019.

  MENUITEMINFO mii = { sizeof(mii) };
  mii.fMask = MIIM_STRING | MIIM_FTYPE | MIIM_ID | MIIM_STATE;
  mii.wID = idCmdFirst + IDM_DISPLAY;
  mii.fType = MFT_STRING;
  mii.dwTypeData = L"&Sample Text";
  mii.fState = MFS_ENABLED;
  if (!InsertMenuItem(hMenu, indexMenu, TRUE, &mii))
  {
    return HRESULT_FROM_WIN32(GetLastError());
  }

The error is Error (active) E0144 a value of type "const wchar_t *" cannot be used to initialize an entity of type "wchar_t *"

According Microsoft documentation, the second one should work. https://docs.microsoft.com/en-us/windows/win32/learnwin32/working-with-strings

Edit: This is not solved by I cannot initializate WCHAR because I cannot change the type as suggested in that answer.

like image 839
workvact Avatar asked Aug 22 '19 14:08

workvact


2 Answers

Some Windows structs are used to both "Get and Set" and string members in these structs point to mutable strings. This is in direct conflict with the compiler/linker settings that store strings literals in read-only memory.

It is theoretically unsafe to use a string literal with the setter function because it might write to the string (and then restore it back to its original content).

The only known place where this happens is the command line parameter in CreateProcessW.

In all other places you can probably just cast away const:

MENUITEMINFO mii = { sizeof(mii) };
mii.dwTypeData = const_cast<LPTSTR>(TEXT("&Sample Text"));
like image 60
Anders Avatar answered Sep 22 '22 08:09

Anders


Be careful! As Lightness Races in Orbit points out, modifying the data you pass could be a problem down the road. Try this, instead:

MENUITEMINFO mii = { sizeof(mii) };
mii.fMask = MIIM_STRING | MIIM_FTYPE | MIIM_ID | MIIM_STATE;
mii.wID = idCmdFirst + IDM_DISPLAY;
mii.fType = MFT_STRING;
wchar_t text[] = L"&Sample Text";
mii.dwTypeData = text;
mii.fState = MFS_ENABLED;

This way, you should be a wee bit safer - but not completely!! As RbMm points out, it is far better as a general rule to have the dwTypeData member pointing to a static character array. Somewhere (outside) the function …

static thread_local wchar_t menuText[MAXTEXTLEN];

Then, set up mii with …

wcscpy(menuText, L"&Sample Text");
mii.dwTypeData = menuText;
mii.cch = MAXTEXTLEN; // But not used in this case!
like image 27
Adrian Mole Avatar answered Sep 19 '22 08:09

Adrian Mole