Преобразовать std::string в STRSAFE_LPCWSTR с помощью служебного метода

#c #winapi

#c #winapi

Вопрос:

Я относительно новичок в C и пробую Windows Notification с использованием Win32 API.
Это метод, который у меня есть:

 BOOL Notification::ShowNotification(std::string title, std::string info) {
  NOTIFYICONDATA nid = {
    sizeof(nid)
  };
  nid.uFlags = NIF_INFO | NIF_GUID;
  nid.guidItem = __uuidof(AppIcon);
  nid.dwInfoFlags = NIIF_USER | NIIF_LARGE_ICON;

  std::wstring wtitle = std::wstring(title.begin(), title.end());
  const wchar_t * wchar_title = (STRSAFE_LPCWSTR) wtitle.c_str();
  StringCchCopy(nid.szInfoTitle, sizeof(nid.szInfoTitle), wchar_title);

  std::wstring wInfo = std::wstring(info.begin(), info.end());
  const wchar_t * wchar_Info = (STRSAFE_LPCWSTR) wInfo.c_str();
  StringCchCopy(nid.szInfo, sizeof(nid.szInfo), wchar_Info);

  LoadIconMetric(g_hInst, MAKEINTRESOURCE(IDI_NOTIFICATIONICON), LIM_LARGE, amp; nid.hBalloonIcon);
  return Shell_NotifyIcon(NIM_MODIFY, amp; nid);
}
  

Как вы можете видеть, существует дублирующий код для преобразования string типа в STRSAFE_LPCWSTR для переменных title и info . Я думал о небольшом служебном методе, который заменил бы дублирующийся код.
Что-то вроде этого:

 void Notification::ConvertToLPCWSTR(std::string input, STRSAFE_LPCWSTR amp;result)
{
  std::wstring wide_string = std::wstring(input.begin(), input.end());
  result = (STRSAFE_LPCWSTR)wide_string.c_str();
}
  

А затем использовать его из ShowNotification метода, подобного этому, где wchar_title передается по ссылке:

 STRSAFE_LPCWSTR wchar_title;
ConvertToLPCWSTR(title, wchar_title);
  

Но это приводит к сбою, потому что wide_string переменная выделяется стеком и выходит из области видимости, когда ConvertToLPCWSTR выполнение завершено, из-за чего wchar_title указывает на освобожденную память.

Кто-нибудь знает хороший способ исправить это?

Комментарии:

1. Почему понижающий голос?

2. Вам не нужны никакие преобразования. Просто исправьте свои интерфейсы, чтобы они принимали правильные строки в кодировке UTF-16 (иначе std::wstring с любым заданным компилятором Windows).

3. std::wstring(info.begin(), info.end()) это неправильный способ преобразования std::string в std::wstring . Это будет работать только для строк ASCII. В противном случае вам необходимо преобразовать данные, используя MultiByteToWideChar() , std::wstring_convert или эквивалент.

Ответ №1:

Вам нужно переместить все три строки повторяющегося кода в небольшую служебную функцию.

 static void Notification::ConvertToLPCWSTR(const std::stringamp; input, LPWSTR result, size_t result_max_size) {
  std::wstring wInfo = std::wstring(input.begin(), input.end());
  const wchar_t * wchar_Info = (STRSAFE_LPCWSTR) wInfo.c_str();
  StringCchCopy(result, result_max_size, wchar_Info);
}
  

И вызвать, как

 ConvertToLPCWSTR(info, nid.szInfo, sizeof(nid.szInfo));
  

Комментарии:

1. Спасибо S.M. Итак, идея заключается в том, чтобы заполнить цель, прежде чем переменная стека выйдет за пределы области видимости, передав саму цель в метод. Я привык в основном работать на C #, где я мог бы просто вернуть преобразованное значение из служебного метода, которое затем будет использоваться вызываемым пользователем.

2. std::wstring wInfo = std::wstring(input.begin(), input.end()) не делает ничего значимого для любой кодировки символов. За исключением ASCII. И да, это выражение настолько неверно, что требует голосования «против».

3. Это преобразование типов данных ( char в wchar_t ), а не преобразование кодировки.