Здравствуйте мне PM поставил задачу:
Сделать так что бы наш проект запускался напрямую со стартима.
Покопавшись в проблеме я увидел что при запуске со стартима, текущая директория указывалась куда попало, сделал так:
Во-первых, либо TCHAR, GetModuleFileName, _tcsstr(path, _T("starbase")), либо char, GetModuleFileNameA, strstr(path, "starbase").
Но это так, мелочи.
Причина же в том, что — по видимому, в релизе из-под стартима длина имени файла оказалась больше, чем MAX_PATH.
Поэтому GetModuleFileName() не дописал туда концевой ноль
lpFilename
A pointer to a buffer that receives the fully-qualified path of the module. If the length of the path exceeds the size that the nSize parameter specifies, the function succeeds, and the string is truncated to nSize characters and cannot be null terminated.
После чего strstr уехал искать конец строки вверх по стеку...
Чтобы проверить это, нужно посмотреть на GetLastError() == ERROR_INSUFFICIENT_BUFFER.
А чтобы пресечь проблемы — достаточно после GetModuleFileName() написать path[MAX_PATH-1]=0.
Хотя по-человечески было бы так
// ATL или MFC CString; при желании можно поплясать вокруг STL и возвращать basic_string<TCHAR>
CString GetModuleFileName(HMODULE hmodule)
{
DWORD len = ::GetModuleFileName(hmodule,NULL,0);
CString path;
::GetModuleFileName(hmodule, path.GetBuffer(len+1), len+1);
path.ReleaseBuffer();
return path;
}
... << RSDN@Home 1.2.0 alpha rev. 655>>
Перекуём баги на фичи!
Re[2]: вылет в strstr в релизной версии
От:
Аноним
Дата:
06.02.08 12:07
Оценка:
Здравствуйте, Кодт, Вы писали:
К>Здравствуйте, <Аноним>, Вы писали:
А>>
К>Во-первых, либо TCHAR, GetModuleFileName, _tcsstr(path, _T("starbase")), либо char, GetModuleFileNameA, strstr(path, "starbase"). К>Но это так, мелочи.
К>Причина же в том, что — по видимому, в релизе из-под стартима длина имени файла оказалась больше, чем MAX_PATH. К>Поэтому GetModuleFileName() не дописал туда концевой ноль К>
К>lpFilename
К>A pointer to a buffer that receives the fully-qualified path of the module. If the length of the path exceeds the size that the nSize parameter specifies, the function succeeds, and the string is truncated to nSize characters and cannot be null terminated.
К>После чего strstr уехал искать конец строки вверх по стеку...
К>Чтобы проверить это, нужно посмотреть на GetLastError() == ERROR_INSUFFICIENT_BUFFER. К>А чтобы пресечь проблемы — достаточно после GetModuleFileName() написать path[MAX_PATH-1]=0.
К>Хотя по-человечески было бы так К>
К>// ATL или MFC CString; при желании можно поплясать вокруг STL и возвращать basic_string<TCHAR>
К>CString GetModuleFileName(HMODULE hmodule)
К>{
К> DWORD len = ::GetModuleFileName(hmodule,NULL,0);
К> CString path;
К> ::GetModuleFileName(hmodule, path.GetBuffer(len+1), len+1);
К> path.ReleaseBuffer();
К> return path;
К>}
К>
Сделал так:
GetModuleFileName(NULL, path, MAX_PATH );
path[MAX_PATH-1]=0;
CString sPath(path);
::MessageBox(NULL, sPath.GetBuffer(),"info",MB_OK);
int pos=sPath.Find("starbase"); //При запуске из стартима вот здесь падаетif(pos>0 )
{
Просто часть пути из стартима возвращается заглавными буквами, но все ровно не могу понять, почему падает и только в релизе. Сделал так заработало:
"starbase" — категорически против такого кода, одни пишет "starbase" другой "StarBase" третий "STARTBASE" а четвертый пишет всегда с ошибками "statbase" ну сколько уже говорить можно ... такие вещи нужно выносить в константы и лучше типизированные ... типа class ConstNameSpace::startBase или т.п.
все эти сишные strstr и т.д. не безопасны, лучше используй stl string find
Здравствуйте, <Аноним>, Вы писали:
А>Сделал так:
А>
А> GetModuleFileName(NULL, path, MAX_PATH );
А> path[MAX_PATH-1]=0;
А> CString sPath(path);
А> ::MessageBox(NULL, sPath.GetBuffer(),"info",MB_OK);
А> int pos=sPath.Find("starbase"); //При запуске из стартима вот здесь падает
А> if(pos>0 )
А> {
А>
Ты хочешь сказать, что CString::Find падает?! Вау.
Кстати говоря, sPath.GetBuffer() — это лишнее. MessageBox'у нужен LPCTSTR, а не LPTSTR.
А не наведённая ли это ошибка, кстати говоря?
Например, ты где-то умудрился расстрелять память, в которой лежит starbase. Например, элементарно затёр концевой ноль:
void killemall()
{
char* victim = "starbase"; // или любым другим способом прицелиться на эту строку
victim[strlen(victim)] = 123;
}
Поскольку компилятор вправе
— размещать строковые литералы как в сегменте констант, так и в сегменте данных
— размещать каждый литерал в отдельном массиве или совмещать одинаковые литералы
то собственно запись в литерал может пройти безболезненно, зато потом узнаешь много новых слов.
Здравствуйте, lifrsdn, Вы писали:
К>>Кстати говоря, sPath.GetBuffer() — это лишнее. MessageBox'у нужен LPCTSTR, а не LPTSTR. L>Не только лишнее, но и пропущен sPath.ReleaseBuffer(). Может из-за этого проблемы?
Мне казалось, что CString терпимо относится к этому делу. Грубо говоря, GetBuffer обеспечивает монопольное владение строкой (поскольку MFC/ATL практикует COW), а ReleaseBuffer выполняет измерение длины и снова разрешает совместное использование.
Здравствуйте, Кодт, Вы писали:
К>>>Кстати говоря, sPath.GetBuffer() — это лишнее. MessageBox'у нужен LPCTSTR, а не LPTSTR. L>>Не только лишнее, но и пропущен sPath.ReleaseBuffer(). Может из-за этого проблемы?
К>Мне казалось, что CString терпимо относится к этому делу. Грубо говоря, GetBuffer обеспечивает монопольное владение строкой (поскольку MFC/ATL практикует COW), а ReleaseBuffer выполняет измерение длины и снова разрешает совместное использование.
Это так, но ReleaseBuffer ещё и устанавливает длину строки. Когда были проблемы, что после неотпущенного буфера, длина строки считалась нулевой, что и приводило к проблемам. Код правда не падал, но как говорится мало ли? Взял — отдай обратно.
S>все эти сишные strstr и т.д. не безопасны, лучше используй stl string find
Ну и инициализировать переменные, проверять код возврата из функций на ошибки, ну и не перемешивать строковые типы TCHAR с CHAR: if(_tcsstr(path,_T("starbase")){.