NO

Author Topic: SHBrowseForFolder() issue: win-7  (Read 8190 times)

triola

  • Guest
SHBrowseForFolder() issue: win-7
« on: July 22, 2014, 02:28:25 AM »
This is a 'mod-loader' for warzone2100 that I've been working on for my grandson.

I built this on XP, it worked fine. However, testing it on 7, I get an error when clicking on the 'MAP' button (it didn't specify what the error was, just that the '...program has encountered an error...'.

There are two functions that are essentially identical, one opens a browse-dialog for the MOD directories (which works on both XP and 7) and the other opens the browse-dialog for C:\Documents and Settings\user\My Documents\\Warzone 2100 3.1\maps .

In 7, Documents and Settings doesn't exist, it's a symlink that's supposed to provide backward compatibility to programs like mine.

showmods:
Code: [Select]
//mod manager, add/delete mods, drag-drop
///////////////////////////////////////////////
int showmods(HWND hwndDlg)
{
    char path[1024];
    char wzpath[1024];
    char instruct[1024];

    LPITEMIDLIST resultInfo, pathinfo;
    BROWSEINFO   bi;
    char         bidisplay[1024];
    char         bititle[1024]  = "Install your MODS to these folders (global works for most):\n";
    ULONG        sfgao          = SFGAO_FILESYSTEM;       
    wchar_t      ws[100];
           
    sprintf(path,"%s\\mods\\global or \\campaign or \\multiplay\n",WZPATH);
    sprintf(wzpath,"%s\\mods",WZPATH);
    sprintf(instruct,"Open Explorer, browse to your saved  *.wz  MODS and drag them to campaign, global or multiplay, below.");


        strcat(bititle,path);
        strcat(bititle,instruct);
        swprintf(ws, 100, L"%hs", wzpath);

bi.hwndOwner      = hwndDlg;
bi.pidlRoot       = NULL;
bi.pszDisplayName = bidisplay;
                        bi.lpszTitle      = bititle;
bi.ulFlags        = BIF_RETURNONLYFSDIRS|BIF_NONEWFOLDERBUTTON|BIF_NEWDIALOGSTYLE|BIF_BROWSEINCLUDEFILES;
bi.lpfn           = NULL;

            SHParseDisplayName(
                              ws,
                              NULL,
                              &pathinfo,
                              sfgao,
                              NULL
                             );
            bi.pidlRoot=pathinfo;
   
            resultInfo =SHBrowseForFolder(&bi);
   
            loadcombo(hmodglobal,  makepath(MODPATH,WZPATH,GLOBAL));
            loadcombo(hmodglobal,  makepath(MODPATH,WZPATH,CAMPAIGN));
            loadcombo(hmodglobal,  makepath(MODPATH,WZPATH,MULTIPLAY));


return 0;
}

showmaps:
Code: [Select]
//map manager, add/delete maps, drag-drop
///////////////////////////////////////////////
int showmaps(HWND hwndDlg)
{
    char path[1024];
    char wzpath[1024];
    char instruct[1024];

    LPITEMIDLIST resultInfo, pathinfo;
    BROWSEINFO   bi;
    char         bidisplay[1024];
    char         bititle[1024]  = "Install your MAPS here:\n";
    ULONG        sfgao          = SFGAO_FILESYSTEM;       
    wchar_t      ws[100];
           
    sprintf(wzpath,"C:\\Documents and Settings\\%s\\My Documents\\Warzone 2100 3.1"  ,USER);
    sprintf(  path,"C:\\Documents and Settings\\%s\\My Documents\\Warzone 2100 3.1\\maps\n",USER);
    sprintf(instruct,"Open Explorer, browse to your saved  *.wz  MAPS and drag them to the maps folder, below.");


        strcat(bititle,path);
        strcat(bititle,instruct);
        swprintf(ws, 100, L"%hs", wzpath);

bi.hwndOwner      = hwndDlg;
bi.pidlRoot       = NULL;
bi.pszDisplayName = bidisplay;
                        bi.lpszTitle      = bititle;
bi.ulFlags        = BIF_RETURNONLYFSDIRS|BIF_NONEWFOLDERBUTTON|BIF_NEWDIALOGSTYLE|BIF_BROWSEINCLUDEFILES;
bi.lpfn           = NULL;

            SHParseDisplayName(
                              ws,
                              NULL,
                              &pathinfo,
                              sfgao,
                              NULL
                             );
            bi.pidlRoot=pathinfo;
   
            resultInfo =SHBrowseForFolder(&bi);


return 0;
}




However, comparing the two functions (and knowing they both work as expected on XP), the only significant difference I see are the paths they access ( showmod() works on both XP and & 7, showmaps() works on XP but not on 7).

Now I haven't done any win-programming in years, so I'm behind the curve on a lot of levels, but can you spot any discrepacies that may be a program-related cause for this behavior on win-7?

Thanks, Tony

PS:  Unfortunately, the only way to put this through it's paces is to have warzone2100 installed, at least temporarily, in order to exercise the directory-finding functions and generate the required ini file.

Project files are attached.


Offline frankie

  • Global Moderator
  • Member
  • *****
  • Posts: 2113
Re: SHBrowseForFolder() issue: win-7
« Reply #1 on: July 22, 2014, 11:45:18 AM »
It seems that on WIN7 the symlinks are no more resolved by SHBrowseForFolder, so you have to solve it by yourself using SHGetFolderLocation or SHGetFolderPath.
You can call SHGetFolderLocation with CSIDL=CSIDL_MYDOCUMENTS to get the item identifier list structure that specifies the folder's location relative to the root to use in the SHBrowseForFolder as starting path.
If you need the path to cat to your full path (as in your example) you have to use SHGetFolderPath to retrieve it. Also in this case the function parameter 'nFolder' is a CSIDL set to CSIDL_MYDOCUMENTS.
As usual new OS's helps to make life easier .....  >:(

EDIT: seems that even SHGetFolderPath don't work, you have to use instead SHGetSpecialFolderPath. >:(
« Last Edit: July 22, 2014, 01:21:19 PM by frankie »
"It is better to be hated for what you are than to be loved for what you are not." - Andre Gide

triola

  • Guest
Re: SHBrowseForFolder() issue: win-7
« Reply #2 on: July 22, 2014, 03:35:00 PM »
Thank you again, frankie, for taking a look.

I suppose the only way I'm going to resolve this is to put my development environment on the win-7 machine so that I can monitor the results of my trial and error.

I just wanted another set of eyes on this code in case I'd done something obviously wrong, as far as the vista/7/8 OSs are concerned.

I'll try your suggestions and keep an eye on the path results, I'm sure that's the issue, I appreciate you pointing out the functions to try.

Off subject, I have to say I really enjoy working in the Pells-C environment. It's very well thought-out, very straight-forward.

In any case, I'll post back with my findings when I run everything down.

Thanks,
Tony

Offline jj2007

  • Member
  • *
  • Posts: 536
Re: SHBrowseForFolder() issue: win-7
« Reply #3 on: July 22, 2014, 04:05:54 PM »
Hi Tony,
This works on Windows 7-32:
Code: [Select]
#include <stdio.h>
#include <ShlObj.h>
#pragma comment(lib, "Ole32.lib")
#pragma comment(lib, "Shell32.lib")
#pragma comment(linker, "/SubSystem:Console")
#pragma warn(disable:2216)    // retval never used

int main(void) {
  BROWSEINFO bi;
  char path[1024];
  char dn[1024];
  bi.hwndOwner = NULL;
  bi.pidlRoot = NULL;
  bi.pszDisplayName = dn;
  bi.lpszTitle = "MyTitle";
  bi.ulFlags = BIF_RETURNONLYFSDIRS|BIF_NONEWFOLDERBUTTON|BIF_NEWDIALOGSTYLE|BIF_BROWSEINCLUDEFILES;
  bi.lpfn = NULL;
  LPITEMIDLIST sbff=SHBrowseForFolder(&bi);
  if (sbff) {
SHGetPathFromIDList(sbff, path);
CoTaskMemFree(sbff);
  }
  printf("Selected folder: [%s]", bi.pszDisplayName);
//   _getch(); // in case your IDE closes the console - needs conio.h
}

There is a known fat bug in SHBrowseForFolder on Win7, but I doubt it's the reason for your problems.

triola

  • Guest
Re: SHBrowseForFolder() issue: win-7
« Reply #4 on: July 22, 2014, 04:27:06 PM »
EDIT: seems that even SHGetFolderPath don't work, you have to use instead SHGetSpecialFolderPath.

Yes, well just to keep us both updated with MS's last round of deprication:

SHGetSpecialFolderPath is not supported. Instead, use ShGetFolderPath.
http://msdn.microsoft.com/en-us/library/windows/desktop/bb762204%28v=vs.85%29.aspx

SHGetFolderPath is Depricated. As of Vista, this is merely a wrapper for SHGetKnownFolderPath.
http://msdn.microsoft.com/en-us/library/windows/desktop/bb762181%28v=vs.85%29.aspx

So now it's SHGetKnownFolderPath, and no more CSIDL, now it's KNOWNFOLDERID.

No telling how long this will last until they change it again.


There is a known fat bug in SHBrowseForFolder on Win7, but I doubt it's the reason for your problems.

Thanks for pointing that out, jj. No, I agree with you that this bug is probably not the issue, it's most certainly to do with my path-building and virtual dirs (symlinks).

I'll put Pelles and warzone on my daughter's win-7 machine and see if I can track it down.
« Last Edit: July 22, 2014, 04:35:57 PM by triola »

JohnF

  • Guest
Re: SHBrowseForFolder() issue: win-7
« Reply #5 on: July 23, 2014, 08:32:53 AM »
Hi Tony,
This works on Windows 7-32:
Code: [Select]
#include <stdio.h>
#include <ShlObj.h>
#pragma comment(lib, "Ole32.lib")
#pragma comment(lib, "Shell32.lib")
#pragma comment(linker, "/SubSystem:Console")
#pragma warn(disable:2216)    // retval never used

int main(void) {
  BROWSEINFO bi;
  char path[1024];
  char dn[1024];
  bi.hwndOwner = NULL;
  bi.pidlRoot = NULL;
  bi.pszDisplayName = dn;
  bi.lpszTitle = "MyTitle";
  bi.ulFlags = BIF_RETURNONLYFSDIRS|BIF_NONEWFOLDERBUTTON|BIF_NEWDIALOGSTYLE|BIF_BROWSEINCLUDEFILES;
  bi.lpfn = NULL;
  LPITEMIDLIST sbff=SHBrowseForFolder(&bi);
  if (sbff) {
SHGetPathFromIDList(sbff, path);
CoTaskMemFree(sbff);
  }
  printf("Selected folder: [%s]", bi.pszDisplayName);
//   _getch(); // in case your IDE closes the console - needs conio.h
}

There is a known fat bug in SHBrowseForFolder on Win7, but I doubt it's the reason for your problems.

I just checked for that bug, it seems ok now.

John

JohnF

  • Guest
Re: SHBrowseForFolder() issue: win-7
« Reply #6 on: July 23, 2014, 09:05:55 AM »
triola,

This works here using CSIDL_MYDOCUMENTS

Code: [Select]
int SHBrowseDir(char *Title, char *result)
{
LPMALLOC pMalloc;
BROWSEINFO browseInfo;
LPITEMIDLIST pidlRoot = NULL;
LPITEMIDLIST ItemIDList;
int r = 0;

if (S_OK != SHGetMalloc(&pMalloc))
return 0;

SHGetFolderLocation(GetActiveWindow(), CSIDL_MYDOCUMENTS, NULL, 0, &pidlRoot);

memset(&browseInfo, 0, sizeof(BROWSEINFO));
browseInfo.hwndOwner = GetActiveWindow();
browseInfo.pszDisplayName = result;
browseInfo.lpszTitle = Title;
browseInfo.ulFlags = BIF_NEWDIALOGSTYLE | BIF_UAHINT;
browseInfo.lpfn = (BFFCALLBACK)BrowseForFolderDlgProc;
browseInfo.lParam = 0;
browseInfo.pidlRoot = pidlRoot;

ItemIDList = SHBrowseForFolder(&browseInfo);

if (ItemIDList != NULL)
{
*result = 0;
if (SHGetPathFromIDList(ItemIDList, result))
{
if (result[0])
r = 1;
pMalloc->lpVtbl->Free(pMalloc,ItemIDList);
}
}
pMalloc->lpVtbl->Release(pMalloc);
return r;
}

John

Offline jj2007

  • Member
  • *
  • Posts: 536
Re: SHBrowseForFolder() issue: win-7
« Reply #7 on: July 23, 2014, 12:33:00 PM »
I just checked for that bug, it seems ok now.

Which Windows version? On Win 7, it's clearly present, although difficult to spot. You basically preset a folder, then display the dialog; if that path happens to be the last in a long list of folders, it won't be visible.

JohnF

  • Guest
Re: SHBrowseForFolder() issue: win-7
« Reply #8 on: July 23, 2014, 12:57:47 PM »
Just realised that by accident I'd put BFFM_SETSELECTION in flags like so

browseInfo.ulFlags = BIF_NEWDIALOGSTYLE | BIF_UAHINT | BFFM_SETSELECTION;

and sent the message from the callback func.

SendMessage(hDlg, BFFM_SETSELECTION, 1, (LPARAM)szPath);

It works.

John

Offline jj2007

  • Member
  • *
  • Posts: 536
Re: SHBrowseForFolder() issue: win-7
« Reply #9 on: July 23, 2014, 01:36:49 PM »
browseInfo.ulFlags = BIF_NEWDIALOGSTYLE | BIF_UAHINT | BFFM_SETSELECTION;
SendMessage(hDlg, BFFM_SETSELECTION, 1, (LPARAM)szPath);

It works.

Interesting - so they fixed it. Which Windows version? Both on Microsoft Social and Microsoft Connect, it's flagged as a bug in Win7 (all versions).

Quote
It's extremely obvious after just a handful of function calls. (Tends to occur in 5+ random calls out of 10.) It is not restricted to Windows 7 x64, but happens on the 32-bit editions as well. And it happens in both 32- and 64-bit applications. The root is insignificant. This isn't related to development environment. It's a Shell problem, pure and simple, and it was introduced in Windows 7.

JohnF

  • Guest
Re: SHBrowseForFolder() issue: win-7
« Reply #10 on: July 23, 2014, 02:16:58 PM »
No it's not fixed, the flags param should not have BFFM_SETSELECTION - it was by accident.

But it works with my accident. :)

Win7

EDIT: I've reduced it to this, instead of using BFFM_SETSELECTION which is not part of flags, but if you use BIF_RETURNONLYFSDIRS instead it works.

browseInfo.ulFlags = BIF_NEWDIALOGSTYLE | BIF_UAHINT | BIF_RETURNONLYFSDIRS;

More appropriate
browseInfo.ulFlags = BIF_NEWDIALOGSTYLE | BIF_UAHINT | 0x1;

John
« Last Edit: July 23, 2014, 07:29:35 PM by JohnF »