2016-02-03 2 views
1

Я хочу, чтобы иметь возможность открыть файл в моем приложении Win32. Метод, который я использую, - это получение корневого пути из поля редактирования, например. «C: \ MyFolder» (присваивается значение strPathToSource). Затем я хочу добавить другую строку, например. «\ source \ Utilities \ File.h» и сохраните конкатенированный путь в новой переменной strPathToFile.Согласование LPTSTR с const char * (Win32 C++)

Таким образом, strPathToFile должен содержать «C: \ MyFolder \ source \ Utilities \ File.h», который затем можно открыть, используя infile.open(strPathToFile).

Соответствующий код показан ниже:

ifstream infile; 

int bufSize = 1024; 
LPTSTR strPathToSource = new TCHAR[bufSize]; 
GetDlgItemText(hWnd, IDC_MAIN_EDIT_FILEPATH, strPathToSource, bufSize); // Get text from edit box and assign to strPathToSource 

const char* strPathToFile = char(strPathToSource) + PATH_TO_FILE; 
infile.open(strPathToFile); 
if(!infile) 
{ 
    log(hWnd, "File.h not found."); 
    return false; 
} 

Где PATH_TO_FILE определяется как:

const char* PATH_TO_FILE = "\\source\\Utilities\\File.h"; 

Моя проблема заключается в том, что она всегда выходить из системы "file.h не найден". Я считаю, что проблема заключается в конкатенации, например.

const char* strPathToFile = char(strPathToSource) + PATH_TO_FILE; 

Пошаговые можно увидеть значение strPathToSource и PATH_TO_FILE являются, как они должны быть, но каскадный результат в strPathToFile имеет значение NULL, я считаю.

+3

Вы не объединяете указатели, используя '+', и вы не смешиваете 'const char *' с 'LPTSTR', так как они разные. Другими словами, ваш код страдает от двух (или более) проблем, которые не связаны друг с другом, но оба могут вызвать проблемы. – PaulMcKenzie

+0

Также - ** никогда ** литые строковые типы. Если компилятор жалуется, что указатели несовместимы, сделайте ** ** ** не отбросить ошибку. Используйте правильные типы строк. – PaulMcKenzie

+0

В Windows лучше не использовать 'std :: ifstream' вообще. Он разбит - по дизайну - из-за отсутствующего конструктора, используя широкую строку символов. Если вы все еще хотите использовать 'std :: ifstream' в Windows, подумайте об использовании расширения Microsoft, которое предоставляет [basic_ifstream c'tor] (https://msdn.microsoft.com/en-us/library/zek0beca.aspx) принимая широкую строку символов. – IInspectable

ответ

2

Добавление двух указателей символов не связывает строки, оно просто добавляет два значения указателя (как «числа»). Таким образом, вы получаете недопустимый указатель.

Кроме того, приведение типов от LPTSTR к char * не является хорошей идеей, так как TCHAR может быть также широким, в зависимости от текущих настроек сборки. (в том, что вы меняете LPTSTR на char, а не на указатель, что еще больше не так)

Я думаю, что проще всего преобразовать обе строки в std :: string (или wstring), там вы может использовать оператор «+» для выполнения конкатенации.

Одна из возможностей сделать это:

const std::wstring strPathToFile = cvt2wstring(strPathToSource) + cvt2wstring(PATH_TO_FILE); 

cvt2wstring определяется как:

#include <codecvt> 
#include <string> 

std::wstring cvt2wstring(const char * str) 
{ 
    std::wstring_convert<std::codecvt_utf8_utf16<wchar_t> > converter; 
    return converter.from_bytes(str); 
} 

std::wstring cvt2wstring(const wchar_t * str) 
{ 
    return str; 
} 

В зависимости от фактического типа, он должен выбрать соответствующую перегрузку.

Для противоположности преобразования в StD :: строки (так что вы можете использовать обычную зЬй :: ifstream) вы можете переключать направление:

std::string cvt2string(const char * str) 
{ 
    return str; 
} 

std::string cvt2string(const wchar_t * str) 
{ 
    std::wstring_convert<std::codecvt_utf8_utf16<wchar_t> > converter; 
    return converter.to_bytes(str); 
} 

Для меня, ifstream :: Open() кажется для работы с wstring (но это может быть расширение MSVC, поскольку стандарт C++ не предусматривает этого - в любом случае, если вы используете TCHAR & comp., вероятно, вы нацелитесь на Windows и MSVC).

+2

Если вы собираетесь использовать TCHAR (я бы этого не сделал. Выберите один и придерживайтесь его - возможно, wchar_t в эти дни), я настоятельно рекомендую определить typedef 'tstring', который является' std :: basic_string '. Таким образом, вам не нужно иметь ifdefs повсюду. –

+0

Спасибо за ваш ответ. Не могли бы вы написать, как вы конвертируете оба в std :: string или wstring? – petehallw

+0

Обратите внимание, что другая проблема с кодом заключается в том, что 'std :: ifstream' принимает только строки, основанные на символах. В зависимости от типа сборки это также нужно будет навязать либо 'std :: ifstream', либо' std :: wifstream'. Вы должны упомянуть об этом в своем ответе. – PaulMcKenzie

1

Мартин Боннер в основном дал правильный ответ.

Короче говоря, лучшим решением является игнорировать TCHAR. Это костыль, относящийся к последнему десятилетию прошлого века, когда Unicode был проблемой для ПК с ОЗУ 4 МБ. Сегодня 4 ГБ распространены, в тысячу раз больше.

Однако, если вы все еще хотите жить в ту эпоху, будьте последовательны.Не определяйте

const char* PATH_TO_FILE = "\\source\\Utilities\\File.h";

но использовать

const TCHAR * PATH_TO_FILE = _T("\\source\\Utilities\\File.h");

Кроме того, научиться использовать конкатенацию. Вы можете использовать std::basic_string<TCHAR>::operator+ (простой) или tcscat (привыкнуть к переполнению буфера).