1. Joseph Vendra
  2. PowerBuilder
  3. Monday, 15 March 2021 05:55 AM UTC

I needed a better select folder dialog option PowerBuilder's default GetFolder option.

The base PB function is too basic in many ways.

I found the "Common Item Dialog" solution Bruce Armstrong presented a while back and after some fiddling got it working the way I needed to but needing to have .NET Framework installed seems overkill, along with the GAC and registry configuration steps to get it work and hopefully my installation program is smart and good enough to get it all done properly for as many windows installs as possible.  That's the problem, so many windows OS install varieties in the user base and trusting that MS wont change something that breaks this important feature ...

I also suspect the .NET version used to compile the FolderBrowser dll was v2 and I have to decide if I should be updating to .net 4 or not before going too much farther down this rabbit hole.

We are talking about the new Select Folder (example below anonymized)

 

vs the PB Stock GetFolder

Is there any other easier "PowerBuilder Only" way to pop open the more enhanced get folder using the updated "Common Item Dialog" using PB only code or functions rather than resorting to anything external?

Does anyone know if Appeon is planning on enhancements to add some additional support for the newer modernized common item dialog's as base calls in PB? (Hint)

Anyone else work with the new updated common item dialog that has any input to share would be appreciated.

 

Thanks

Accepted Answer
Joseph Vendra Accepted Answer Pending Moderation
  1. Monday, 15 March 2021 18:55 PM UTC
  2. PowerBuilder
  3. # Permalink

I tried your solution but it was not quite what I needed because I really need the best quality of network population as possible. It was an improvement but not quite there.

I have another challenge now,Trying to get FolderBrowser2 to optionally set the InitialDirectory to some directory other than the last folder it was in when it was last used. 

Joseph

Comment
  1. Miguel Leeuwe
  2. Monday, 15 March 2021 23:47 PM UTC
Try calling the ChangeDirectory() function before using the FolderBrowser.

Maybe it'll fix the problem (if the FolderBrowser itself doesn't change any 'internal' directories by accessing files.

regards.
  1. Helpful
  1. Joseph Vendra
  2. Tuesday, 16 March 2021 17:37 PM UTC
No, none of that matters to this call inside that visual studio dll it will not care what your apps current directory is only what the last used folder the common item dialog used.

SetCurrentDirectory or ChangeDirectory all did not work.

However, good news is it was much simpler than i imagined, I just opened the FolderBrowser2 sample source in Visual Studios 2019 and modified the FolderBrowser2.cs source script to add a few lines and updated the ShowDialog() to add another string argument, tested the directory provided if it was valid and now if we pass in a valid UNC or Directory path on the machine the PB app is run on the dialog is now opening to the directory desired.

Its really the best solution so far so I am just going to run with it.

Thanks for the suggestions guys I was just trying to avoid modifying the original sample dll but life is never as easy as that anyhow its done.



sample of the updated FolderBrowser2.cs that works to add the parm for setting the default folder:



using System;

using System.Runtime.InteropServices;

using System.IO;



namespace FolderBrowser2

{

public class FolderBrowser2

{

public string DirectoryPath { get; set; }



public int ShowDialog( ulong handle, string strStartPath){



IntPtr hwndOwner = (IntPtr)handle;



IFileOpenDialog dialog = (IFileOpenDialog)new FileOpenDialog();

try

{

IShellItem item;



if (!string.IsNullOrEmpty(strStartPath))

{

if (Directory.Exists(strStartPath))

{

DirectoryPath = strStartPath;

}

}





if (!string.IsNullOrEmpty(DirectoryPath))

{

IntPtr idl;

uint atts = 0;

if (SHILCreateFromPath(DirectoryPath, out idl, ref atts) == 0)

{

if (SHCreateShellItem(IntPtr.Zero, IntPtr.Zero, idl, out item) == 0)

{

dialog.SetFolder(item);

}

}

}

dialog.SetOptions(FOS.FOS_PICKFOLDERS | FOS.FOS_FORCEFILESYSTEM);

uint hr = dialog.Show(hwndOwner);

if (hr == ERROR_CANCELLED)

return FB2_CANCEL;



if (hr != 0)

return FB2_ERROR;



dialog.GetResult(out item);

string path;

item.GetDisplayName(SIGDN.SIGDN_FILESYSPATH, out path);

DirectoryPath = path;

return FB2_SUCCESS;

}

finally

{

Marshal.ReleaseComObject(dialog);

}

}



[DllImport("shell32.dll")]

private static extern int SHILCreateFromPath([MarshalAs(UnmanagedType.LPWStr)] string pszPath, out IntPtr ppIdl, ref uint rgflnOut);



[DllImport("shell32.dll")]

private static extern int SHCreateShellItem(IntPtr pidlParent, IntPtr psfParent, IntPtr pidl, out IShellItem ppsi);



[DllImport("user32.dll")]

private static extern IntPtr GetActiveWindow();



private const uint ERROR_CANCELLED = 0x800704C7;

private const int FB2_SUCCESS = 1;

private const int FB2_CANCEL = 0;

private const int FB2_ERROR = -1;



[ComImport]

[Guid("DC1C5A9C-E88A-4dde-A5A1-60F82A20AEF7")]

private class FileOpenDialog

{

}



[ComImport]

[Guid("42f85136-db7e-439c-85f1-e4075d135fc8")]

[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]

private interface IFileOpenDialog

{

[PreserveSig]

uint Show([In] IntPtr parent); // IModalWindow

void SetFileTypes(); // not fully defined

void SetFileTypeIndex([In] uint iFileType);

void GetFileTypeIndex(out uint piFileType);

void Advise(); // not fully defined

void Unadvise();

void SetOptions([In] FOS fos);

void GetOptions(out FOS pfos);

void SetDefaultFolder(IShellItem psi);

void SetFolder(IShellItem psi);

void GetFolder(out IShellItem ppsi);

void GetCurrentSelection(out IShellItem ppsi);

void SetFileName([In, MarshalAs(UnmanagedType.LPWStr)] string pszName);

void GetFileName([MarshalAs(UnmanagedType.LPWStr)] out string pszName);

void SetTitle([In, MarshalAs(UnmanagedType.LPWStr)] string pszTitle);

void SetOkButtonLabel([In, MarshalAs(UnmanagedType.LPWStr)] string pszText);

void SetFileNameLabel([In, MarshalAs(UnmanagedType.LPWStr)] string pszLabel);

void GetResult(out IShellItem ppsi);

void AddPlace(IShellItem psi, int alignment);

void SetDefaultExtension([In, MarshalAs(UnmanagedType.LPWStr)] string pszDefaultExtension);

void Close(int hr);

void SetClientGuid(); // not fully defined

void ClearClientData();

void SetFilter([MarshalAs(UnmanagedType.Interface)] IntPtr pFilter);

void GetResults([MarshalAs(UnmanagedType.Interface)] out IntPtr ppenum); // not fully defined

void GetSelectedItems([MarshalAs(UnmanagedType.Interface)] out IntPtr ppsai); // not fully defined

}



[ComImport]

[Guid("43826D1E-E718-42EE-BC55-A1E261C37BFE")]

[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]

private interface IShellItem

{

void BindToHandler(); // not fully defined

void GetParent(); // not fully defined

void GetDisplayName([In] SIGDN sigdnName, [MarshalAs(UnmanagedType.LPWStr)] out string ppszName);

void GetAttributes(); // not fully defined

void Compare(); // not fully defined

}



private enum SIGDN : uint

{

SIGDN_DESKTOPABSOLUTEEDITING = 0x8004c000,

SIGDN_DESKTOPABSOLUTEPARSING = 0x80028000,

SIGDN_FILESYSPATH = 0x80058000,

SIGDN_NORMALDISPLAY = 0,

SIGDN_PARENTRELATIVE = 0x80080001,

SIGDN_PARENTRELATIVEEDITING = 0x80031001,

SIGDN_PARENTRELATIVEFORADDRESSBAR = 0x8007c001,

SIGDN_PARENTRELATIVEPARSING = 0x80018001,

SIGDN_URL = 0x80068000

}



[Flags]

private enum FOS

{

FOS_ALLNONSTORAGEITEMS = 0x80,

FOS_ALLOWMULTISELECT = 0x200,

FOS_CREATEPROMPT = 0x2000,

FOS_DEFAULTNOMINIMODE = 0x20000000,

FOS_DONTADDTORECENT = 0x2000000,

FOS_FILEMUSTEXIST = 0x1000,

FOS_FORCEFILESYSTEM = 0x40,

FOS_FORCESHOWHIDDEN = 0x10000000,

FOS_HIDEMRUPLACES = 0x20000,

FOS_HIDEPINNEDPLACES = 0x40000,

FOS_NOCHANGEDIR = 8,

FOS_NODEREFERENCELINKS = 0x100000,

FOS_NOREADONLYRETURN = 0x8000,

FOS_NOTESTFILECREATE = 0x10000,

FOS_NOVALIDATE = 0x100,

FOS_OVERWRITEPROMPT = 2,

FOS_PATHMUSTEXIST = 0x800,

FOS_PICKFOLDERS = 0x20,

FOS_SHAREAWARE = 0x4000,

FOS_STRICTFILETYPES = 4

}

}

}

  1. Helpful
  1. Miguel Leeuwe
  2. Wednesday, 17 March 2021 22:54 PM UTC
Glad you solved it and thanks for sharing!
  1. Helpful
There are no comments made yet.
Roland Smith Accepted Answer Pending Moderation
  1. Monday, 15 March 2021 12:40 PM UTC
  2. PowerBuilder
  3. # 1

I have a PB only GetFolder replacement:

https://www.topwizprogramming.com/freecode_getfolder.html

The network node is populated from the recents dropdown at the top of Windows Explorer which stores them in the registry. I couldn't get the network functions to work 100% of the time and when they did work they were too slow.

 

Comment
There are no comments made yet.
Chris Pollach @Appeon Accepted Answer Pending Moderation
  1. Monday, 15 March 2021 20:02 PM UTC
  2. PowerBuilder
  3. # 2

Hi Joseph;

  FWIW: I have had a Get Folder dialogue working in my STD Framework since 2012. Have a look at the "of_browse_for_folder" method in the "nc_app_controller_master" ancestor object within the STD_FC_PB_BASE.pbl" library.

  The "of_browse_for_folder" method uses the SHBrowseForFolder and SHGetPathFromIDList MS-Windows API's and thus no .NET framework is required.

  I would suggest down loading the STD FC Demo App (OrderEntry) that also includes the framework. Have a look at the "Open" event of the Demo App's Application Controller called "nc_ac_orderentry" in the "OES_Main.pbl" library. In the oe_open event of that NVUO, un-comment the following "Test Case" code ...

    String            ls_path
    ls_path        =    THIS.of_browse_for_folder  ( "Temp" )
    IF  IsNull ( ls_path ) = TRUE  THEN
        MessageBox ( "You chose to Cancel", "No path selected!"  )
    else
        MessageBox ( "You chose", ls_path )
    END IF

  That should show you how to call & use the "of_browse_for_folder" method.  Since the framework is free & open source, feel free to grab the code you need and add that to your PB App(s) to implement this functionality.  HTH

FYI: http://sourceforge.net/projects/stdfndclass/files/Applications/PowerBuilder/OrderEntry

Regards ... Chris

 TIP: By Changing the uFlags setting in the structure before calling those API's, you can get get more options and even a more modern look. Also, you can Browse for Computers or even Browse for Printers. Check out the MSDN link below.

lstr_bi.si_ulFlags  = 1  // Change as follows ...

http://docs.microsoft.com/en-us/windows/win32/api/shlobj_core/ns-shlobj_core-browseinfoa

 

 

Comment
There are no comments made yet.
  • Page :
  • 1


There are no replies made for this question yet.
However, you are not allowed to reply to this question.