0

I'm trying to apply file's extension filters to the file's selection dialog.

This way works:

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";

enter image description here

But when I'm assigning extension filters dynamically, via parameters, it fails, filters don't appear in the combo box:

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();

enter image description here

I'm assuming the problem is in strings conversion, but can't figure it out.

ProtectedVoid
  • 1,293
  • 3
  • 17
  • 42
  • Not tested, I guess the separator `'\0'` may do harm to `stringstream`. If so, how about using another character such as `$` as separator, and after finished building the filter, copy the string to an array of `char` and convert `$`s to `'\0'`? – MikeCAT Dec 04 '15 at 16:06
  • Have you tried looking at `ffilter` in the debugger to see what it contains? – Mark Ransom Dec 04 '15 at 16:13
  • Any news here? People are waiting... :) – Vlad Feinstein Dec 11 '15 at 12:47

4 Answers4

2

This line:

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

Is passing null-terminated char* strings to operator<<(), and thus is effectively behaving the same as this code at runtime:

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

The nulls never make it into s.

To insert the nulls correctly, you need to assign them to the stringstream as individual char values and not as char* values:

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

Also, the fact that you are type-casting extFilter is suspicious. If you have to do that to get rid of a compiler error then extFilter is not a compatible data type to begin with, the type-cast is hiding a bug in your code. Get rid of the type-cast:

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

If the code fails to compile then you are doing something wrong and need to fix it properly.

On the other hand, if extFilter is a null-terminated char string to begin with, you don't need to assign it to a variable before passing it to operator<<():

s << "(*.exe) Windows Executable" << '\0' << "*." << extFilter << '\0';
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
0

You are using a pointer to some temporary string that, according to http://www.cplusplus.com/reference/string/string/c_str/, "may be invalidated by further calls to other member functions that modify the object."

Vlad Feinstein
  • 10,960
  • 1
  • 12
  • 27
  • The "any further method calls" is unlikely, as there might not be any. More likely is that the temporary stringstream itself went out of scope and got freed. – andlabs Dec 04 '15 at 16:55
  • 1
    There is no temporary involved. The `stringstream` content is being assigned to a `string` variable that stays in scope until the dialog is dismissed. – Remy Lebeau Dec 04 '15 at 17:02
  • @RemyLebeau - That's a good guess, but I don't see a call to a dialog in the posted fragment. – Vlad Feinstein Dec 04 '15 at 17:16
  • @VladFeinstein: We can clearly see an `OPENFILENAME` variable being used, and we know that has to remain in scope until the dialog closes. And we can see the filter being assigned to a local `string` variable and that variable then assigned to the `OFN` variable. So unless the `string` variable is inside of curly braces and the `OFN` variable is outside of those braces, the `string` data is in scope during the dialog call. – Remy Lebeau Dec 04 '15 at 17:28
  • @RemyLebeau - if the problem was only with the 0-separators, as you suggest in your answer, the OP would likely get ONE incomplete filter, starting with `(*.exe) Windows Executable`, but NOT the garbage at the very first byte. – Vlad Feinstein Dec 04 '15 at 17:42
0

Finally found an answer:

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){
. . .
ProtectedVoid
  • 1,293
  • 3
  • 17
  • 42
0

A shorter version:

ofn.lpstrFilter = _T("Format: XML\0*.xml\0");
Bugs
  • 4,491
  • 9
  • 32
  • 41