[bmx] Modern RequestDir :- RequestFolder by col [ 1+ years ago ]

Started by BlitzBot, June 29, 2017, 00:28:38

Previous topic - Next topic

BlitzBot

Title : Modern RequestDir :- RequestFolder
Author : col
Posted : 1+ years ago

Description : Should be compatible with all Windows versions
The RequestDir requester looks out of data now-a-days on Vista and Win7 so I knocked up a quick solution for a more modern looking requester which will fall back to the original one for older OS's.

RequestFolder$(Title$,InitialPath$)

This can be used as a direct replacement for the RequestDir function.

[EDIT 06 Apr 17]
Added a requester to let you select multiple files at the same time. The results are returned as a string array.

RequestFiles$[](Title$,InitialPath$)


Code :
Code (blitzmax) Select
Strict

?Win32

Import "-lole32"
Import Pub.Win32

Global Shell32Dll = LoadLibraryA("Shell32.dll")
Global SHCreateItemFromParsingName(pszPath$w,pbc:Byte Ptr,riid:Byte Ptr,ppv:IUnknown Var)"Win32" = GetProcAddress(Shell32Dll,"SHCreateItemFromParsingName")

Global CLSID_FileOpenDialog[] = [$dc1c5a9c,$4ddee88a,$f860a1a5,$f7ae202a]
Global IID_IFileOpenDialog[] = [$d57c7288,$4768d4ad,$969d02be,$60d93295]
Global IID_IShellItem[] = [$43826d1e,$42eee718,$e2a155bc,$fe7bc361]


Extern"Win32"
'These types are INCOMPLETE - DO NOT USE FOR ANYTHING ELSE !!!!!!
Type IModalWindow Extends IUnknown
Method Show(hWnd)
EndType

Type IFileDialog Extends IModalWindow
Method SetFileTypes()
Method SetFileTypeIndex()
Method GetFileTypeIndex()
Method Advise()
Method Unadvise()
Method SetOptions(dwOptions)
Method GetOptions(dwOptions Ptr)
Method SetDefaultFolder(pShellItem:Byte Ptr)
Method SetFolder(pSI:Byte Ptr)
Method GetFolder()
Method GetCurrentSelection()
Method SetFilename(pszName$w)
Method GetFileName()
Method SetTitle(pszName$w)
Method SetOKButtonLabel()
Method SetFilenameLabel()
Method GetResult(pItem:IShellItem Var)
Method AddPlace()
Method SetDefaultExtension()
Method Close()
Method SetClientGuid()
Method ClearClientData()
Method SetFilter()
EndType

Type IFileOpenDialog Extends IFileDialog
Method GetResults(ppEnum:IShellItemArray Ptr)
Method GetSelectedItems(ppsai:IShellItemArray Ptr)
EndType

Type IShellItemArray Extends IUnknown
Method BindToHandler()
Method GetPropertyStore()
Method GetPropertyDescriptionList()
Method GetAttributes()
Method GetCount(pdwNumItems:Int Ptr)
Method GetItemAt(dwIndex:Int, ppsi:IShellItem Ptr)
Method EnumItems()
EndType

Type IShellItem Extends IUnknown
Method BindToHandler()
Method GetParent()
Method GetDisplayName(sigdnName,ppszName:Short Ptr Var)
Method GetAttributes()
Method Compare()
EndType

Function CoCreateInstance(rclsid:Byte Ptr,pUnkOuter:Byte Ptr,dwClsContext,riid:Byte Ptr,ppv:IUnknown Var) 'My version
Function CoInitialize(pvReserved)
Function CoUninitialize()
EndExtern

Function RequestFiles:String[](title:String, initialPath:String)
Global pDialog:IFileOpenDialog
Global pInitialPath:IShellItem
Global pResults:IShellItemArray
Local hr:Int

CoInitialize(0)

hr = CoCreateInstance(CLSID_FileOpenDialog,Null,CLSCTX_INPROC_SERVER,IID_IFileOpenDialog,pDialog)
If hr < 0
CleanUp()
Return Null
EndIf

Local dwOptions:Int
pDialog.GetOptions(Varptr dwOptions)
pDialog.SetOptions(dwOptions|$200) ' $200 = FOS_ALLOWMULTISELECT

'Create an IShellItem for a default folder path
InitialPath = Replace(InitialPath,"/","")
SHCreateItemFromParsingName(InitialPath,Null,IID_IShellItem,pInitialPath)

If pDialog.SetFolder(pInitialPath) < 0
CleanUp()
Return [RequestFile(Title,InitialPath)]
EndIf

' show it
pDialog.SetTitle(Title)
pDialog.Show(0)

' get the result
If pDialog.GetResults(Varptr pResults) < 0
CleanUp()
Return Null
EndIf

'Get the results
Local count:Int
If pResults.GetCount(Varptr count) < 0
CleanUp()
Return Null
EndIf

Local selectedItemNames:String[count]
For Local i:Int = 0 Until count
Local pItem:IShellItem
If pResults.getItemAt(i, Varptr pItem) >= 0
Local pName:Short Ptr
pItem.GetDisplayName($80058000,pName)
selectedItemNames[i] = String.FromWString(pName)
EndIf

If pItem pItem.Release_()
Next

CleanUp()
Return selectedItemNames

Function CleanUp()
If pDialog
pDialog.Release_()
pDialog = Null
EndIf
If pInitialPath
pInitialPath.Release_()
pInitialPath = Null
EndIf
If pResults
pResults.Release_()
pResults = Null
EndIf
CoUninitialize()
EndFunction
EndFunction


Function RequestFolder$(Title$,InitialPath$)
Global pDialog:IFileOpenDialog
Global pInitialPath:IShellItem
Global pFolder:IShellItem
Local hr,ResultFolder$

CoInitialize(0)

'Create Instance of the Dialog
hr = CoCreateInstance(CLSID_FileOpenDialog,Null,CLSCTX_INPROC_SERVER,IID_IFileOpenDialog,pDialog)

'Not on Vista or Win7?
If hr < 0 CleanUp(); Return RequestDir(Title,InitialPath)

'Set it to Browse Folders
Local dwOptions
pDialog.GetOptions(Varptr dwOptions)
pDialog.SetOptions(dwOptions|$20)

'Set Title
pDialog.SetTitle(Title)

'Create an IShellItem for a default folder path
InitialPath = Replace(InitialPath,"/","")
SHCreateItemFromParsingName(InitialPath,Null,IID_IShellItem,pInitialPath)

If pDialog.SetFolder(pInitialPath) < 0
CleanUp()
Return RequestDir(Title,InitialPath)
EndIf

'Show the Dialog
pDialog.Show(0)

'Test the result
If pDialog.GetResult(pFolder) < 0
CleanUp
Return ""
EndIf

'Get the result
Local pName:Short Ptr
pFolder.GetDisplayName($80058000,pName)
ResultFolder = String.FromWString(pName)

CleanUp()
Return ResultFolder

Function CleanUp()
If pDialog
pDialog.Release_()
pDialog = Null
EndIf
If pInitialPath
pInitialPath.Release_()
pInitialPath = Null
EndIf
If pFolder
pFolder.Release_()
pFolder = Null
EndIf
CoUninitialize()
EndFunction
EndFunction
?

'Example Usage
Print RequestFolder("Select a Folder...","")
Local files:String[] = RequestFiles("Select some file(s)","")
For Local file:String = EachIn files
Print file
Next


Comments :


TomToad(Posted 1+ years ago)

 got an EAV on this pInitialPath.Release_ after clicking on "Select Folder".Windows 7 64 bit sp1


col(Posted 1+ years ago)

 UpdatedI've changed the code to include error checking and tidied it up a little.@TomToadYou would have got the EAV if you didn't supply a valid InitialPath. All fixed now.


col(Posted 1+ years ago)

 Works Ok on Win8 too.


col(Posted 2 months ago)

 Fixed a subtle bug...As long as a user selected a folder then all is ok.However if a user decided to cancel selecting a folder after the 2nd time this had been called then an EAV would pop up.Also added a file requestor to let you select multiple files simultaneouslyNote the plural function name and a string array is returned : RequestFiles:String[](title:String, initialPath:String)Any probs let me know.


Ryszard

Good morning!

Very nice code. I use it in my technical drawing processing program. On the old version of BlitzMax it works without any problems. Unfortunately, it needs more memory and faster speed for large drawings. I switched to BlitzMax NG 64-bit. During compilation I got this message: unable to convert from byte ptr to int blitzmax. I tried the advice I found on the web. Without result. I am asking for advice.

Derron

The code needs a little bit of an overhaul to get it working on NG.

some "types" would now be called "interface", you need to make it "superstrict" to see differences - as some stuff is using "integer" as default while it should be "byte ptr" and other stuff.

I changed some lines but still get an EAV on startup - so surely missed a lot of stuff to change.

Code (BlitzMax) Select

SuperStrict
Framework Brl.StandardIO
Import Brl.SystemDefault 'RequestDir()

?Win32

Import "-lole32"
Import Pub.Win32

Global Shell32Dll:Byte Ptr = LoadLibraryA("Shell32.dll")
Global SHCreateItemFromParsingName(pszPath$w,pbc:Byte Ptr,riid:Byte Ptr,ppv:IUnknown_ Var)"Win32" = GetProcAddress(Shell32Dll,"SHCreateItemFromParsingName")

Global CLSID_FileOpenDialog:Int[] = [$dc1c5a9c,$4ddee88a,$f860a1a5,$f7ae202a]
Global IID_IFileOpenDialog:Int[] = [$d57c7288,$4768d4ad,$969d02be,$60d93295]
Global IID_IShellItem:Int[] = [$43826d1e,$42eee718,$e2a155bc,$fe7bc361]


Extern"Win32"
        'These types are INCOMPLETE - DO NOT USE FOR ANYTHING ELSE !!!!!!
        Interface IModalWindow Extends IUnknown_
                Method Show(hWnd:Byte Ptr)
        EndInterface

        Interface IFileDialog Extends IModalWindow
                Method SetFileTypes()
                Method SetFileTypeIndex()
                Method GetFileTypeIndex()
                Method Advise()
                Method Unadvise()
                Method SetOptions(dwOptions:Int)
                Method GetOptions(dwOptions:Int Ptr)
                Method SetDefaultFolder(pShellItem:Byte Ptr)
                Method SetFolder:Int(pSI:Byte Ptr)
                Method GetFolder()
                Method GetCurrentSelection()
                Method SetFilename(pszName$w)
                Method GetFileName()
                Method SetTitle(pszName$w)
                Method SetOKButtonLabel()
                Method SetFilenameLabel()
                Method GetResult:Int(pItem:IShellItem Var)
                Method AddPlace()
                Method SetDefaultExtension()
                Method Close()
                Method SetClientGuid()
                Method ClearClientData()
                Method SetFilter()
        EndInterface
       
        Interface IFileOpenDialog Extends IFileDialog
                Method GetResults:Int(ppEnum:IShellItemArray Ptr)
                Method GetSelectedItems(ppsai:IShellItemArray Ptr)
        EndInterface
       
        Interface IShellItemArray Extends IUnknown_
                Method BindToHandler()
                Method GetPropertyStore()
                Method GetPropertyDescriptionList()
                Method GetAttributes()
                Method GetCount:Int(pdwNumItems:Int Ptr)
                Method GetItemAt:Int(dwIndex:Int, ppsi:IShellItem Ptr)
                Method EnumItems()
        EndInterface
       
        Interface IShellItem Extends IUnknown_
                Method BindToHandler()
                Method GetParent()
                Method GetDisplayName(sigdnName:Int,ppszName:Short Ptr Var)
                Method GetAttributes()
                Method Compare()
        EndInterface
       
        Function CoCreateInstance:Byte Ptr(rclsid:Byte Ptr,pUnkOuter:Byte Ptr,dwClsContext:Byte Ptr,riid:Byte Ptr,ppv:IUnknown_ Var)="HRESULT CoCreateInstance(REFCLSID, LPUNKNOWN, DWORD, REFIID, LPVOID)!"
        Function CoInitialize:Byte Ptr(pvReserved:Byte Ptr)="HRESULT CoInitialize(LPVOID)!"
        Function CoUninitialize()="void CoUninitialize()!"
EndExtern

Function RequestFiles:String[](title:String, initialPath:String)
        Global pDialog:IFileOpenDialog
        Global pInitialPath:IShellItem
        Global pResults:IShellItemArray
        Local hr:Byte Ptr
       
        CoInitialize(0)

        hr = CoCreateInstance(CLSID_FileOpenDialog,Null,CLSCTX_INPROC_SERVER,IID_IFileOpenDialog,pDialog)
        If hr < 0
                CleanUp()
                Return Null
        EndIf
       
        Local dwOptions:Int
        pDialog.GetOptions(Varptr dwOptions)
        pDialog.SetOptions(dwOptions|$200) ' $200 = FOS_ALLOWMULTISELECT

        'Create an IShellItem for a default folder path
        InitialPath = InitialPath.Replace("/","\")
        SHCreateItemFromParsingName(InitialPath,Null,IID_IShellItem,pInitialPath)
       
        If pDialog.SetFolder(pInitialPath) < 0
                CleanUp()
                Return [RequestFile(Title,InitialPath)]
        EndIf

        ' show it
        pDialog.SetTitle(Title)
        pDialog.Show(0)

        ' get the result
        If pDialog.GetResults(Varptr pResults) < 0
                CleanUp()
                Return Null
        EndIf
       
        'Get the results
        Local count:Int
        If pResults.GetCount(Varptr count) < 0
                CleanUp()
                Return Null
        EndIf

        Local selectedItemNames:String[count]
        For Local i:Int = 0 Until count
                Local pItem:IShellItem
                If pResults.getItemAt(i, Varptr pItem) >= 0
                        Local pName:Short Ptr
                        pItem.GetDisplayName($80058000,pName)
                        selectedItemNames[i] = String.FromWString(pName)
                EndIf

                If pItem pItem.Release_()
        Next   
       
        CleanUp()
        Return selectedItemNames
       
        Function CleanUp()
                If pDialog
                        pDialog.Release_()
                        pDialog = Null
                EndIf
                If pInitialPath
                        pInitialPath.Release_()
                        pInitialPath = Null
                EndIf
                If pResults
                        pResults.Release_()
                        pResults = Null
                EndIf
                CoUninitialize()
        EndFunction   
EndFunction


Function RequestFolder$(Title$,InitialPath$)
        Global pDialog:IFileOpenDialog
        Global pInitialPath:IShellItem
        Global pFolder:IShellItem
        Local hr:Byte Ptr
Local ResultFolder$

        CoInitialize(0)

        'Create Instance of the Dialog
        hr = CoCreateInstance(CLSID_FileOpenDialog,Null,CLSCTX_INPROC_SERVER,IID_IFileOpenDialog,pDialog)

        'Not on Vista or Win7?
        If hr < 0 CleanUp(); Return RequestDir(Title,InitialPath)
       
        'Set it to Browse Folders
        Local dwOptions:Int
        pDialog.GetOptions(Varptr dwOptions)
        pDialog.SetOptions(dwOptions|$20)
       
        'Set Title
        pDialog.SetTitle(Title)
       
        'Create an IShellItem for a default folder path
        InitialPath = InitialPath.Replace("/","\")
        SHCreateItemFromParsingName(InitialPath,Null,IID_IShellItem,pInitialPath)
       
        If pDialog.SetFolder(pInitialPath) < 0
                CleanUp()
                Return RequestDir(Title,InitialPath)
        EndIf
               
        'Show the Dialog
        pDialog.Show(0)

        'Test the result
        If pDialog.GetResult(pFolder) < 0
                CleanUp
                Return ""
        EndIf
       
        'Get the result
        Local pName:Short Ptr
        pFolder.GetDisplayName($80058000,pName)
        ResultFolder = String.FromWString(pName)
       
        CleanUp()
        Return ResultFolder
       
        Function CleanUp()
                If pDialog
                        pDialog.Release_()
                        pDialog = Null
                EndIf
                If pInitialPath
                        pInitialPath.Release_()
                        pInitialPath = Null
                EndIf
                If pFolder
                        pFolder.Release_()
                        pFolder = Null
                EndIf
                CoUninitialize()
        EndFunction
EndFunction
?

'Example Usage
Print RequestFolder("Select a Folder...","")
Local files:String[] = RequestFiles("Select some file(s)","")
For Local file:String = EachIn files
        Print file
Next


Mine fails at "If pDialog.SetFolder(pInitialPath) < 0"

col

Thanks Derron - you were almost there!
Just for you reference - return values (HRESULT hr) for COM functions/methods are 32bit Ints (long in c).

The remaining culprits were

Method SetDefaultFolder(pShellItem:Byte Ptr)
Method SetFolder:Int(pSI:Byte Ptr)

to this

Method SetDefaultFolder(pShellItem:IShellItem)
Method SetFolder:Int(pSI:IShellItem)


Complete example now checked and working with x86 and x64.


SuperStrict
Framework Brl.StandardIO
Import Brl.SystemDefault 'RequestDir()

?Win32

Import "-lole32"
Import Pub.Win32

Global Shell32Dll:Byte Ptr = LoadLibraryA("Shell32.dll")
Global SHCreateItemFromParsingName:Int(pszPath$w,pbc:Byte Ptr,riid:Byte Ptr,ppv:IUnknown_ Var)"Win32" = GetProcAddress(Shell32Dll,"SHCreateItemFromParsingName")

Global CLSID_FileOpenDialog:Int[] = [$dc1c5a9c,$4ddee88a,$f860a1a5,$f7ae202a]
Global IID_IFileOpenDialog:Int[] = [$d57c7288,$4768d4ad,$969d02be,$60d93295]
Global IID_IShellItem:Int[] = [$43826d1e,$42eee718,$e2a155bc,$fe7bc361]


Extern"Win32"
        'These types are INCOMPLETE - DO NOT USE FOR ANYTHING ELSE !!!!!!
        Interface IModalWindow Extends IUnknown_
                Method Show(hWnd:Byte Ptr)
        EndInterface

        Interface IFileDialog Extends IModalWindow
                Method SetFileTypes()
                Method SetFileTypeIndex()
                Method GetFileTypeIndex()
                Method Advise()
                Method Unadvise()
                Method SetOptions:Int(dwOptions:Int)
                Method GetOptions:Int(dwOptions:Int Ptr)
                Method SetDefaultFolder:Int(pShellItem:IShellItem)
                Method SetFolder:Int(pSI:IShellItem)
                Method GetFolder()
                Method GetCurrentSelection()
                Method SetFilename:Int(pszName$w)
                Method GetFileName()
                Method SetTitle:Int(pszName$w)
                Method SetOKButtonLabel()
                Method SetFilenameLabel()
                Method GetResult:Int(pItem:IShellItem Var)
                Method AddPlace()
                Method SetDefaultExtension()
                Method Close()
                Method SetClientGuid()
                Method ClearClientData()
                Method SetFilter()
        EndInterface
       
        Interface IFileOpenDialog Extends IFileDialog
                Method GetResults:Int(ppEnum:IShellItemArray Ptr)
                Method GetSelectedItems:Int(ppsai:IShellItemArray Ptr)
        EndInterface
       
        Interface IShellItemArray Extends IUnknown_
                Method BindToHandler()
                Method GetPropertyStore()
                Method GetPropertyDescriptionList()
                Method GetAttributes()
                Method GetCount:Int(pdwNumItems:Int Ptr)
                Method GetItemAt:Int(dwIndex:Int, ppsi:IShellItem Ptr)
                Method EnumItems()
        EndInterface
       
        Interface IShellItem Extends IUnknown_
                Method BindToHandler()
                Method GetParent()
                Method GetDisplayName:Int(sigdnName:Int,ppszName:Short Ptr Var)
                Method GetAttributes()
                Method Compare()
        EndInterface
       
        Function CoCreateInstance:Int(rclsid:Byte Ptr,pUnkOuter:Byte Ptr,dwClsContext:Byte Ptr,riid:Byte Ptr,ppv:IUnknown_ Var)="HRESULT CoCreateInstance(REFCLSID, LPUNKNOWN, DWORD, REFIID, LPVOID)!"
        Function CoInitialize:Int(pvReserved:Byte Ptr)="HRESULT CoInitialize(LPVOID)!"
        Function CoUninitialize()="void CoUninitialize()!"
EndExtern

Function RequestFiles:String[](title:String, initialPath:String)
        Global pDialog:IFileOpenDialog
        Global pInitialPath:IShellItem
        Global pResults:IShellItemArray
        Local hr:Byte Ptr
       
        CoInitialize(0)

        hr = CoCreateInstance(CLSID_FileOpenDialog,Null,CLSCTX_INPROC_SERVER,IID_IFileOpenDialog,pDialog)
        If hr < 0
Cleanup()
Return [RequestFile(Title,InitialPath)]
        EndIf
       
        Local dwOptions:Int
        pDialog.GetOptions(Varptr dwOptions)
        pDialog.SetOptions(dwOptions|$200) ' $200 = FOS_ALLOWMULTISELECT

        'Create an IShellItem for a default folder path
        InitialPath = InitialPath.Replace("/","\")
        If SHCreateItemFromParsingName(InitialPath,Null,IID_IShellItem,pInitialPath) < 0
Cleanup()
Return [RequestFile(Title,InitialPath)]
EndIf

        If pDialog.SetFolder(pInitialPath) < 0
                CleanUp()
                Return [RequestFile(Title,InitialPath)]
        EndIf

        ' show it
        pDialog.SetTitle(Title)
        pDialog.Show(0)

        ' get the result
        If pDialog.GetResults(Varptr pResults) < 0
                CleanUp()
                Return Null
        EndIf
       
        'Get the results
        Local count:Int
        If pResults.GetCount(Varptr count) < 0
                CleanUp()
                Return Null
        EndIf

        Local selectedItemNames:String[count]
        For Local i:Int = 0 Until count
                Local pItem:IShellItem
                If pResults.getItemAt(i, Varptr pItem) >= 0
                        Local pName:Short Ptr
                        pItem.GetDisplayName($80058000,pName)
                        selectedItemNames[i] = String.FromWString(pName)
                EndIf

                If pItem pItem.Release_()
        Next 
       
        CleanUp()
        Return selectedItemNames
       
        Function CleanUp()
                If pDialog
                        pDialog.Release_()
                        pDialog = Null
                EndIf
                If pInitialPath
                        pInitialPath.Release_()
                        pInitialPath = Null
                EndIf
                If pResults
                        pResults.Release_()
                        pResults = Null
                EndIf
                CoUninitialize()
        EndFunction   
EndFunction


Function RequestFolder$(Title$,InitialPath$)
        Global pDialog:IFileOpenDialog
        Global pInitialPath:IShellItem
        Global pFolder:IShellItem
        Local hr:Int
        Local ResultFolder$

        CoInitialize(0)

        'Create Instance of the Dialog
        hr = CoCreateInstance(CLSID_FileOpenDialog,Null,CLSCTX_INPROC_SERVER,IID_IFileOpenDialog,pDialog)

        'Not on Vista or Win7?
        If hr < 0
CleanUp()
Return RequestDir(Title,InitialPath)
EndIf
       
        'Set it to Browse Folders
        Local dwOptions:Int
        pDialog.GetOptions(Varptr dwOptions)
        pDialog.SetOptions(dwOptions|$20)
       
        'Set Title
        pDialog.SetTitle(Title)

        'Create an IShellItem for a default folder path
        InitialPath = InitialPath.Replace("/","\")
        hr = SHCreateItemFromParsingName(InitialPath, Null, IID_IShellItem, pInitialPath)
       
        If pDialog.SetFolder(pInitialPath) < 0
                CleanUp()
                Return RequestDir(Title,InitialPath)
        EndIf
               
        'Show the Dialog
        pDialog.Show(0)

        'Test the result
        If pDialog.GetResult(pFolder) < 0
                CleanUp
                Return ""
        EndIf
       
        'Get the result
        Local pName:Short Ptr
        pFolder.GetDisplayName($80058000,pName)
        ResultFolder = String.FromWString(pName)
       
        CleanUp()
        Return ResultFolder
       
        Function CleanUp()
                If pDialog
                        pDialog.Release_()
                        pDialog = Null
                EndIf
                If pInitialPath
                        pInitialPath.Release_()
                        pInitialPath = Null
                EndIf
                If pFolder
                        pFolder.Release_()
                        pFolder = Null
                EndIf
                CoUninitialize()
        EndFunction
EndFunction
?

'Example Usage
Print RequestFolder("Select a Folder...","")
Local files:String[] = RequestFiles("Select some file(s)","")
For Local file:String = EachIn files
        Print file
Next
https://github.com/davecamp

"When you observe the world through social media, you lose your faith in it."

Ryszard


Ryszard

Passes the corrected code and lines it on this line

Local foto: TPixmap = LoadPixmap (file)

in my code by reporting a bug

Compile Error

Type 'tpixmap' not found.

Please give me some suggestions

Derron

If you use the "framework" command, you need to import the used modules on your own.

import brl.pixmap


bye
Ron

Ryszard

Thank you very much for information. My program now works as I wanted.