Winapi GetOpenFileName Extension Filter не работает

Я пытаюсь применить фильтры расширения файла к диалоговому окну выбора файла.

Так работает:

ofn.lpstrFilter =   
"(*.exe) Windows Executable\0*.exe\0"
"(*.ini) Windows Initialization file \0*.ini\0"
"(*.dll) Dynamic Link Library \0*.dll\0"
"(*.lib) Windows Library file \0*.lib\0"
"(*.conf) Windows Configuration file \0*.conf\0";

введите здесь описание изображения

Но когда я назначаю фильтры расширения динамически, через параметры, это не удается, фильтры не отображаются в поле со списком:

LPCSTR filter = (LPCSTR)extFilter; //Contains string "bmp"

stringstream s;
s << "(*.exe) Windows Executable\0" << "*." << filter << "\0";
string ffilter = s.str();
ofn.lpstrFilter = ffilter.c_str();

введите здесь описание изображения

Я предполагаю, что проблема в преобразовании строк, но не могу понять.


person ProtectedVoid    schedule 04.12.2015    source источник
comment
Не проверено, полагаю, что разделитель '\0' может навредить stringstream. Если да, как насчет использования другого символа, такого как $, в качестве разделителя, и после завершения построения фильтра скопировать строку в массив char и преобразовать $s в '\0'?   -  person MikeCAT    schedule 04.12.2015
comment
Вы пытались посмотреть ffilter в отладчике, чтобы узнать, что он содержит?   -  person Mark Ransom    schedule 04.12.2015
comment
Есть новости здесь? Люди ждут ... :)   -  person Vlad Feinstein    schedule 11.12.2015


Ответы (4)


Эта строка:

s << "(*.exe) Windows Executable\0" << "*." << filter << "\0";

Передает char* строки с завершающим нулем в operator<<() и, таким образом, ведет себя так же, как этот код во время выполнения:

s << "(*.exe) Windows Executable" << "*." << filter << "";

Нули никогда не попадают в s.

Чтобы правильно вставить нули, вам нужно назначить их stringstream как отдельные char значения, а не как char* значения:

s << "(*.exe) Windows Executable" << '\0' << "*." << filter << '\0';

Также подозрительно то, что вы приводите extFilter типы. Если вам нужно сделать это, чтобы избавиться от ошибки компилятора, то extFilter не является совместимым типом данных для начала, преобразование типов скрывает ошибку в вашем коде. Избавьтесь от приведения типов:

LPCSTR filter = extFilter; //Contains string "bmp"

Если код не компилируется, значит, вы делаете что-то не так и вам нужно исправить это должным образом.

С другой стороны, если extFilter является строкой с завершающим нулем char для начала, вам не нужно назначать ее переменной перед передачей в operator<<():

s << "(*.exe) Windows Executable" << '\0' << "*." << extFilter << '\0';
person Remy Lebeau    schedule 04.12.2015

Вы используете указатель на некоторую временную строку, которая, согласно http://www.cplusplus.com/reference/string/string/c_str/, «может стать недействительным при дальнейших вызовах других функций-членов, которые изменяют объект».

person Vlad Feinstein    schedule 04.12.2015
comment
Дальнейшие вызовы методов маловероятны, так как их может и не быть. Более вероятно, что сам временный поток строк вышел из области видимости и был освобожден. - person andlabs; 04.12.2015
comment
Нет никакого временного участия. Содержимое stringstream назначается переменной string, которая остается в области видимости, пока диалоговое окно не будет закрыто. - person Remy Lebeau; 04.12.2015
comment
@RemyLebeau - Это хорошее предположение, но я не вижу вызова диалогового окна в опубликованном фрагменте. - person Vlad Feinstein; 04.12.2015
comment
@VladFeinstein: Мы ясно видим, что используется переменная OPENFILENAME, и мы знаем, что она должна оставаться в области видимости до закрытия диалогового окна. И мы видим, что фильтр назначается локальной переменной string, а затем эта переменная назначается переменной OFN. Таким образом, если переменная string не находится внутри фигурных скобок, а переменная OFN не находится вне этих фигурных скобок, данные string находятся в области видимости во время вызова диалога. - person Remy Lebeau; 04.12.2015
comment
@RemyLebeau - если проблема была только с разделителями 0, как вы предлагаете в своем ответе, OP, скорее всего, получит ОДИН неполный фильтр, начинающийся с (*.exe) Windows Executable, но НЕ мусор в самом первом байте. - person Vlad Feinstein; 04.12.2015

Наконец нашел ответ:

const char * extensionFilter = myParamVar; //Contains "JPG" string

string sFilter;
sFilter.append("Format: ");
sFilter.append(extensionFilter);
sFilter.push_back('\0');
sFilter.append("*.");
sFilter.append(extensionFilter);
sFilter.push_back('\0');

//Current filter content --> Format: JPG\0*.JPG\0

const char * filter = sFilter.c_str(); //Char string conversion
ofn.lpstrFilter = filter; //Set the filter to the sctructure's member.

//Opens the dialog and it successfully applies the filter.
if (GetOpenFileName(&ofn)==TRUE){
. . .
person ProtectedVoid    schedule 11.12.2015

Более короткая версия:

ofn.lpstrFilter = _T("Format: XML\0*.xml\0");
person dan shirron    schedule 01.08.2017