я использую GetOpenFileName
функция от Winapi
и я применяю фильтр к диалогу выбора файла.
ЭТОТ работает отлично:
LPSTR mfilter = "Filter\0*.PDF\0";
ofn.lpstrFilter = mfilter;
if(GetOpenFileName(&ofn)){
...
ЭТОТ не удается (диалоговое окно открывается, но фильтры не применяются):
string mfilter = "Filter\0*.PDF\0";
ofn.lpstrFilter = mfilter.c_str();
if(GetOpenFileName(&ofn)){
...
Мне нужно использовать std:string
потому что я получаю расширение файла через параметры и этот тип облегчает конкатенацию, но у меня возникают проблемы несовместимости …
Это был бы мой код, если бы он работал как ожидалось (ОШИБКА такая же, как в предыдущем примере):
const char * ext = &(4:); //Ampersand parameter (from CA Plex) It contains "PDF"string mfilter = "Filter\0*." + ext + "\0"; //Final string: Filter\0*.PDF\0;
ofn.lpstrFilter = mfilter.c_str();
Когда я использую этот метод, я получаю исключение во время выполнения:
string mf;
mf.append("Filter")
.append('\0')
.append("*.pdf")
.append('\0');
ofn.lpstrFilter = mf.c_str();
GetOpenFileName
функция использует TCHAR, и TCHAR становятся WCHAR в случае UNICODE набор символов используется.
Вот пример:
std::wstring getOpenFileName(HWND hWnd, const std::wstring& sFilter)
{
wchar_t buffer[MAX_PATH] = L"";
OPENFILENAMEW ofn = {0};
ofn.lStructSize = sizeof(ofn);
ofn.hwndOwner = hWnd;
ofn.lpstrFilter = sFilter.c_str();
ofn.nFilterIndex = 1;
ofn.lpstrFile = buffer;
ofn.nMaxFile = MAX_PATH;
ofn.Flags = OFN_HIDEREADONLY | OFN_FILEMUSTEXIST;
if( !::GetOpenFileNameW( &ofn ) )
return L"";
return buffer;
}
Если вы хотите параметризовать lpstrFilter
основанный на std::wstring
Вы можете просто использовать wstring::c_str()
получить LPCTSTR
который const wchar*
в случае UNICODE.
ВАЖНЫЙ: Проблема в том, что std::wstring
конструктор, который принимает const wchar*
предполагает, что ввод является строкой C. Строки C заканчиваются на «\ 0» и, таким образом, синтаксический анализ останавливается, когда он достигает символа «\ 0». Чтобы компенсировать это, вы должны использовать конструктор, который принимает два параметра указатель на массив символов и длину.
Вы также можете использовать string::push_back()
метод для добавления NULL.
std::wstring sFilter = L"PDF Files";
sFilter.push_back('\0');
sFilter.append(L"*.pdf");
sFilter.push_back('\0');
С
string mfilter = "Filter\0*.PDF\0";
ты звонишь std::string
contructor, который завершает строку в первом \0
,
Следующий код:
string mfilter = "Filter\0*.PDF\0";
cout << "string:" << mfilter << " len: " << mfilter.length() << endl;
печать
string: Filter len: 6
Строка строится только до первого \0
терминатор. У строки состоит только слово «Фильтр».
string mfilter = "Filter\0*.PDF\0";
Это называется std::basic_string
конструктор, который использует строка с нулевым символом в конце. Это прекратит синтаксический анализ строкового литерала в "Filter"
,
Попробуйте это вместо этого:
string mfilter( "Filter\0*.PDF", 13 ); // need double null at end
Это называется std::basic_string
конструктор, который использует msgstr «первое число символов строки символов, на которые указывает s. s может содержать нулевые символы.»
Вы должны сами посчитать символы или написать код-обертку, если вы сталкиваетесь с этой проблемой чаще.
Связанные с: std::basic_string
конструкторы.
Что касается вашей ошибки во время выполнения:
string mf;
mf.append("Filter")
.append('\0')
.append("*.pdf")
.append('\0');
append()
не имеет перегрузка для одного символьного типа. Вы, вероятно, бьете const CharT* s
перегрузка с нулевым указателем.
Используйте либо append( 1, '\0' )
или же append( "", 1 )
, любой из которых должен добавить нулевой байт.