Question

I have the SHBrowseForFolder to popup and work fine, but I would like to set the Title. I know it has to be a wchar_t* and when I use a const like (wchar_t*)L"My Title" the title is shown correct.

But if I try to use a String value I only get the first letter 'M', it's like the wide string has been converted to new wide string once again, pading each character with a nul.

Winapi::Shlobj::BROWSEINFO bi = {0};
bi.hwndOwner = Handle;
bi.ulFlags = BIF_NEWDIALOGSTYLE | BIF_EDITBOX | BIF_BROWSEFORCOMPUTER;
bi.lpszTitle = String("My Title").w_str(); // This only shows the 'M'
//bi.lpszTitle = (wchar_t*)"My Title";       // This shows the full string 'My Title'
LPITEMIDLIST pidl = SHBrowseForFolder((_browseinfoA*)&bi);

if ( pidl != 0 ) {

  // free memory used
  IMalloc *imalloc = 0;
  if (SUCCEEDED(SHGetMalloc(&imalloc))) {
    imalloc->Free(pidl);
    imalloc->Release();
  }
}

The documentation for UnicodeString all conversion functions c_str(),t_str() and w_str() all returns a wchar_t* but the declaration shows WideChar*.

Any ideas how to make this code work together with a String?

Was it helpful?

Solution

The fact that you are type-casting your bi variable to a _browseinfoA* when calling SHBrowseForFolder() tells me that the "_TCHAR maps to" option in your Project Options is set to "char" instead of "wchar_t". That means your code is actually calling SHBrowseForFolderA() instead of SHBrowseForFolderW(). In XE2, the Winapi::Shlobj::BROWSEINFO structure always maps to ::BROWSEINFOW, regardless of the _TCHAR setting. BROWSEINFOW is a Unicode structure, not an ANSI structure. So you are forcing Unicode data to be passed to an Ansi function. Yes, there is extra padding that is truncating the data, because you are passing the wrong data in the first place.

You need to stop using type-casts. They are hiding errors in your code that the compiler would normally have complained about. C/C++ is a strongly typed language. Using type-casts bypasses the compiler's data type validations.

To fix your code, you need to either:

1) use the generic BROWSEINFO structure from the global namespace instead of the Winapi::Shlobj namespace, so it matches the encoding of the generic SHBrowseForFolder() function:

::BROWSEINFO bi = {0}; 
bi.hwndOwner = Handle; 
bi.ulFlags = BIF_NEWDIALOGSTYLE | BIF_EDITBOX | BIF_BROWSEFORCOMPUTER; 
bi.lpszTitle = TEXT("My Title");
LPITEMIDLIST pidl = SHBrowseForFolder(&bi); 
if ( pidl != NULL ) { 
    // free memory used 
    CoTaskMemFree(pidl); 
} 

2) continue using BROWSEINFO from the Winapi::Shlobj namespace but call SHBrowseForFolderW() directly instead to match the Unicode encoding:

Winapi::Shlobj::BROWSEINFO bi = {0};  
bi.hwndOwner = Handle;  
bi.ulFlags = BIF_NEWDIALOGSTYLE | BIF_EDITBOX | BIF_BROWSEFORCOMPUTER;  
bi.lpszTitle = L"My Title";
LPITEMIDLIST pidl = SHBrowseForFolderW(&bi);  
if ( pidl != NULL) {  
    // free memory used  
    CoTaskMemFree(pidl);  
}

On a separate note, regardless of which approach you take, you cannot use a temporary String as the Title value. The String will go out of scope before SHBrowseForFolder() is called, leaving the BROWSEINFO::lpszTitle field pointing at invalid memory. If you want to use a String then you need to use a local variable for it, eg:

String sTitle = "My Title";
...
bi.lpszTitle = sTitle.c_str();
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top