#visual-c #code-analysis
Вопрос:
Пример кода:
void CMeetingScheduleAssistantDlg::CreateBackupTrayNotification(CString strInfoTitle, CString strInfo, CString strTip)
{
::ZeroMemory(amp;m_sNTD, sizeof(NOTIFYICONDATA));
m_sNTD.cbSize = sizeof(NOTIFYICONDATA);
m_sNTD.hWnd = GetSafeHwnd();
m_sNTD.uID = 0;
m_sNTD.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP | NIF_INFO;
m_sNTD.dwInfoFlags = NIIF_INFO;
m_sNTD.uCallbackMessage = WM_MSA_BACKUP_NOTIFICATION;
m_sNTD.uTimeout = 20000; // 20 Seconds
m_sNTD.hIcon = LoadIcon(AfxGetResourceHandle(),
MAKEINTRESOURCE(IDR_MAINFRAME));
_tcscpy_s(m_sNTD.szInfoTitle, gsl::narrow<rsize_t>(strInfoTitle.GetLength()) 1, (LPCTSTR)strInfoTitle);
_tcscpy_s(m_sNTD.szInfo, gsl::narrow<rsize_t>(strInfo.GetLength()) 1, (LPCTSTR)strInfo);
_tcscpy_s(m_sNTD.szTip, gsl::narrow<rsize_t>(strTip.GetLength()) 1, (LPCTSTR)strTip);
Shell_NotifyIcon(NIM_ADD, amp;m_sNTD);
}
Игнорируйте (LPCTSTR)
приведения, потому что я добавил глобальное pragma
значение для игнорирования предупреждений. Мой вопрос здесь относится к этим строкам:
_tcscpy_s(m_sNTD.szInfoTitle, gsl::narrow<rsize_t>(strInfoTitle.GetLength()) 1, (LPCTSTR)strInfoTitle);
_tcscpy_s(m_sNTD.szInfo, gsl::narrow<rsize_t>(strInfo.GetLength()) 1, (LPCTSTR)strInfo);
_tcscpy_s(m_sNTD.szTip, gsl::narrow<rsize_t>(strTip.GetLength()) 1, (LPCTSTR)strTip);
m_sNTD
является NOTIFYICONDATA
структурой:
typedef struct _NOTIFYICONDATAA {
DWORD cbSize;
HWND hWnd;
UINT uID;
UINT uFlags;
UINT uCallbackMessage;
HICON hIcon;
#if ...
CHAR szTip[64];
#else
CHAR szTip[128];
#endif
DWORD dwState;
DWORD dwStateMask;
CHAR szInfo[256];
union {
UINT uTimeout;
UINT uVersion;
} DUMMYUNIONNAME;
CHAR szInfoTitle[64];
DWORD dwInfoFlags;
GUID guidItem;
HICON hBalloonIcon;
} NOTIFYICONDATAA, *PNOTIFYICONDATAA;
Я получаю страшное предупреждение о распаде указателя (C26485). Как вы можете видеть, рассматриваемые переменные-члены:
CHAR szInfoTitle[64];
CHAR szInfo[256];
CHAR szTip[128];
Примечание: не уверен if ...
, о чем это. Кроме того, моя структура фактически указывает на a NOTIFYICONDATAW
, поэтому переменные-члены WCHAR
.
В любом случае, я понимаю, что я могу подавить предупреждение о распаде указателя, используя amp;varname[0]
. Но в этом случае он не работает:
_tcscpy_s(m_sNTD.amp;szInfoTitle[0], gsl::narrow<rsize_t>(strInfoTitle.GetLength()) 1, (LPCTSTR)strInfoTitle);
_tcscpy_s(m_sNTD.amp;szInfo[0], gsl::narrow<rsize_t>(strInfo.GetLength()) 1, (LPCTSTR)strInfo);
_tcscpy_s(m_sNTD.amp;szTip[0], gsl::narrow<rsize_t>(strTip.GetLength()) 1, (LPCTSTR)strTip);
Ответ №1:
Правильное место для amp;
было бы:
_tcscpy_s(amp;m_sNTD.szInfoTitle[0], gsl::narrow<rsize_t>(strInfoTitle.GetLength()) 1, (LPCTSTR)strInfoTitle);
_tcscpy_s(amp;m_sNTD.szInfo[0], gsl::narrow<rsize_t>(strInfo.GetLength()) 1, (LPCTSTR)strInfo);
_tcscpy_s(amp;m_sNTD.szTip[0], gsl::narrow<rsize_t>(strTip.GetLength()) 1, (LPCTSTR)strTip);
Но на самом деле вы используете _tcscpy_s
неправильно. Второй параметр — размер буфера назначения, а не источника. _s
функции должны быть безопасными, проверяя размер буфера; солгав об этом, вы нарушаете цель этой безопасности.
Просто опустите второй параметр и дайте ему быть выведенным, это также должно исправить предупреждение (действительно исправить, а не подавить):
_tcscpy_s(m_sNTD.szInfoTitle, (LPCTSTR)strInfoTitle);
_tcscpy_s(m_sNTD.szInfo, (LPCTSTR)strInfo);
_tcscpy_s(m_sNTD.szTip, (LPCTSTR)strTip);
Комментарии:
1. Спасибо за пояснения и исправления! Ошибался все эти годы!