- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
We are porting our old DOS code to Windows and use a simple dialog application that perfectly serves for almost all of our tasks.
The problems are following:
1. how to fill the list box with the list of files of any chosen by the user directory. I found the description of DlgDirList function, but have problems to call it from the dialog application.
2. what is the best way to merge selected files in the list box into one (like 'copy a+b c') and use this temporal file for calculations, i.e not to invoke old DOS commands with SYSTEM calls.
Thank you. Any hints or samples would be well received.
Andrei Nikouline
okean@compuserve.com
The problems are following:
1. how to fill the list box with the list of files of any chosen by the user directory. I found the description of DlgDirList function, but have problems to call it from the dialog application.
2. what is the best way to merge selected files in the list box into one (like 'copy a+b c') and use this temporal file for calculations, i.e not to invoke old DOS commands with SYSTEM calls.
Thank you. Any hints or samples would be well received.
Andrei Nikouline
okean@compuserve.com
Link Copied
9 Replies
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Here's a sample code using DlgDirList in a dialog based application:
Few notes:
- As you can see, you must call DlgDirList in dialog initialization callback. It will fail in the main routine, because at that moment dialog is not alive yet.
- Since DlgDirList won't fill DLG_NUMITEMS property for the list, you can't retrieve the selected strings (the list box is Multiple selection) using DlgGet. You have to do it using SendMessage while dialog (and thus list) is still alive. In the sample, it's in callback for OK button, of course, it could be any callback.
- In the sample, current directory cannot be changed. You may provide, say,
a "Browse" button which will call ShBrowseForFolder in order to enable user to change current directory. Unfortunately, I don't have a sample for ShBrowseForFolder at hand (my regular machine is dead by Monday at least);please repost if you're interested.
- Finally, you may consider using GetOpenFileName with OFN_ALLOWMULTISELECT flag, which would provide you full functionality you need instead of coping with DlgDirList.
As for merging files, I don't have any better idea currently.
HTH
Jugoslav
iDummy=DlgInit(IDD_DIALOG1, Dlg) iDummy=DlgSetSub(Dlg, IDD_DIALOG1, OnDlgInit) iDummy=DlgSetSub(Dlg, IDOK, OnDlgOK) iDummy=DlgModal(Dlg) CALL DlgUnInit(Dlg) !================================================ SUBROUTINE OnDlgInit(Dlg, ID, iEvent) USE DFWIN USE DFLOGM INCLUDE "Resource.fd" TYPE(DIALOG):: Dlg INTEGER:: ID, iEvent CHARACTER(MAX_PATH):: szCurrDir, szPathSpec INTEGER:: iDummy szPathSpec = "*.*"//CHAR(0) !iDummy = GetCurrentDirectory(MAX_PATH, szCurrDir) !szPathSpec = szCurrDir(1:SCAN(szCurrDir,CHAR(0))-1) !szPathSpec = TRIM(szCurrDir)//"*.*"//CHAR(0) iDummy=DlgDirList(Dlg%hWnd, szPathSpec, IDC_LIST1, 0, & DDL_ARCHIVE.OR.DDL_READWRITE) END SUBROUTINE OnDlgInit !================================================ SUBROUTINE OnDlgOK(Dlg, ID, iEvent) USE DFWIN USE DFLOGM INCLUDE "Resource.fd" TYPE(DIALOG):: Dlg INTEGER:: ID, iEvent INTEGER:: iDummy, nItems, i CHARACTER(32):: szFile nItems=SendMessage(GetDlgItem(Dlg%hWnd,IDC_LIST1), LB_GETCOUNT, 0, 0) DO i=0,nItems-1 iDummy=SendMessage(GetDlgItem(Dlg%hWnd,IDC_LIST1), LB_GETSEL, i, 0) IF (iDummy.NE.0) THEN !Item is selected iDummy=SendMessage(GetDlgItem(Dlg%hWnd,IDC_LIST1), LB_GETTEXT, i, LOC(szFile)) !Cut trailing char(0) from szFile szFile=szFile(1:SCAN(szFile,CHAR(0))-1) !TODO Do something with szFile here END IF END DO CALL DlgExit(Dlg) END SUBROUTINE OnDlgOK
Few notes:
- As you can see, you must call DlgDirList in dialog initialization callback. It will fail in the main routine, because at that moment dialog is not alive yet.
- Since DlgDirList won't fill DLG_NUMITEMS property for the list, you can't retrieve the selected strings (the list box is Multiple selection) using DlgGet. You have to do it using SendMessage while dialog (and thus list) is still alive. In the sample, it's in callback for OK button, of course, it could be any callback.
- In the sample, current directory cannot be changed. You may provide, say,
a "Browse" button which will call ShBrowseForFolder in order to enable user to change current directory. Unfortunately, I don't have a sample for ShBrowseForFolder at hand (my regular machine is dead by Monday at least);please repost if you're interested.
- Finally, you may consider using GetOpenFileName with OFN_ALLOWMULTISELECT flag, which would provide you full functionality you need instead of coping with DlgDirList.
As for merging files, I don't have any better idea currently.
HTH
Jugoslav
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Jugoslav, thank you a lot for the sample and advice.
This kind of help is invaluable for beginners in API like me.
DlgDirList works fine now and I'd like to confirm my interest in the mentioned by you sample for ShBrowseForFolder.
>you may consider using GetOpenFileName with
>OFN_ALLOWMULTISELECT flag, which would provide you full
>functionality you need instead of coping with DlgDirList.
After declaring the flags in the structure as ofn%Flags = IOR(OFN_ALLOWMULTISELECT,(IOR(OFN_EXPLORER,OFN_READONLY)))
we obtain the string with the path to folder and selected files divided by NULLs. Here are two questions more.
1. Following CVF sample, when I try to change the declaration of the string variable to return the file specification from 'character*512 :: file_spec' to 'character(len=*)...' the compiler doesn't permit it and it would be convenient to have variable length regarding the number of selected files we could have (up to 200).
2. As far as I understand, now we need to parse this string into an array
containing file names with unknown length and size. Is there any special function to perform this action or should I parse 'manually', calculating first the number of substrings (filenames), maximum substring length and then allocating and filling correspondent array?
TIA, Andrei
okean@compuserve.com
This kind of help is invaluable for beginners in API like me.
DlgDirList works fine now and I'd like to confirm my interest in the mentioned by you sample for ShBrowseForFolder.
>you may consider using GetOpenFileName with
>OFN_ALLOWMULTISELECT flag, which would provide you full
>functionality you need instead of coping with DlgDirList.
After declaring the flags in the structure as ofn%Flags = IOR(OFN_ALLOWMULTISELECT,(IOR(OFN_EXPLORER,OFN_READONLY)))
we obtain the string with the path to folder and selected files divided by NULLs. Here are two questions more.
1. Following CVF sample, when I try to change the declaration of the string variable to return the file specification from 'character*512 :: file_spec' to 'character(len=*)...' the compiler doesn't permit it and it would be convenient to have variable length regarding the number of selected files we could have (up to 200).
2. As far as I understand, now we need to parse this string into an array
containing file names with unknown length and size. Is there any special function to perform this action or should I parse 'manually', calculating first the number of substrings (filenames), maximum substring length and then allocating and filling correspondent array?
TIA, Andrei
okean@compuserve.com
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
!======================================================================
SUBROUTINE OnBrowse(Dlg,ID,iAction)
USE DFWIN
USE DLGMOD
USE GLOBALS
USE STRINGS
IMPLICIT NONE
TYPE(Dialog):: Dlg
INTEGER,INTENT(IN):: ID,iAction
TYPE T_BROWSEINFO
INTEGER hwndOwner
INTEGER pidlRoot
INTEGER pszDisplayName ! Return display name of item selected.
INTEGER lpszTitle ! text to go in the banner over the tree.
INTEGER ulFlags ! Flags that control the return stuff
INTEGER lpfn
INTEGER lParam ! extra info that's passed back in callbacks
INTEGER iImage ! output var: where to return the Image index.
END TYPE T_BROWSEINFO
TYPE T_SHITEMID ! mkid
INTEGER(2) cb ! size of identifier, including cb itself
BYTE abID ! variable length item identifier
END TYPE T_SHITEMID
!DEC$OBJCOMMENT LIB: 'OLE32.lib'
INTERFACE
INTEGER FUNCTION SHBrowseForFolder(BI)
!MS$ATTRIBUTES STDCALL,ALIAS: '_SHBrowseForFolderA@4':: SHBrowseForFolder
INTEGER BI
END FUNCTION SHBrowseForFolder
END INTERFACE
INTERFACE
INTEGER FUNCTION SHGetPathFromIDList(lpIDList,szDir)
!MS$ATTRIBUTES STDCALL,ALIAS: '_SHGetPathFromIDListA@8':: SHGetPathFromIDList
!MS$ATTRIBUTES REFERENCE:: szDir
INTEGER lpIDList
CHARACTER*(*) szDir
END FUNCTION
END INTERFACE
INTERFACE
SUBROUTINE CoTaskMemFree(lpIDList)
!MS$ATTRIBUTES STDCALL,ALIAS: '_CoTaskMemFree@4':: CoTaskMemFree
INTEGER lpIDList
END SUBROUTINE
END INTERFACE
CHARACTER*15:: szHeader='Select Folder'C
TYPE (T_BROWSEINFO):: BI
INTEGER:: lpIDList,iSt
LOGICAL:: bSt
INTERFACE
INTEGER FUNCTION BrowseCallbackProc(hwnd, uMsg, lp, pData)
!DEC$ATTRIBUTES STDCALL:: BrowseCallbackProc
INTEGER:: hWnd, uMsg, lp, pData
END FUNCTION
END INTERFACE
INCLUDE 'Resource.fd'
szInitDir=TRIM(szInitDir)//CHAR(0)
BI%hwndOwner=Dlg%hWnd
BI%pidlRoot=NULL
BI%pszDisplayName=LOC(szInitDir)
BI%lpszTitle=LOC(szHeader)
BI%ulFlags=0
BI%lpfn=LOC(BrowseCallbackProc)
BI%lParam=0
BI%iImage=0
lpIDList=SHBrowseForFolder(LOC(BI))
bSt=SHGetPathFromIDList(lpIDList,szInitDir)
CALL CoTaskMemFree(lpIDList)
CALL C2F(szInitDir)
iSt=DlgSet(Dlg,IDC_EDIT_DIR,szInitDir)
CALL FindFilesInDir(Dlg,szInitDir)
END SUBROUTINE OnBrowse
!=================================================
INTEGER FUNCTION BrowseCallbackProc(hwnd, uMsg, lp, pData)
!DEC$ATTRIBUTES STDCALL:: BrowseCallbackProc
USE GLOBALS
IMPLICIT NONE
INTEGER:: hWnd, uMsg, lp, pData
INTEGER:: iSt
! message from browser
INTEGER, PARAMETER:: BFFM_INITIALIZED =1
INTEGER, PARAMETER:: BFFM_SELCHANGED =2
! messages to browser
INTEGER, PARAMETER:: BFFM_SETSTATUSTEXTA =(WM_USER + 100)
INTEGER, PARAMETER:: BFFM_ENABLEOK =(WM_USER + 101)
INTEGER, PARAMETER:: BFFM_SETSELECTIONA =(WM_USER + 102)
INTEGER, PARAMETER:: BFFM_SETSELECTIONW =(WM_USER + 103)
INTEGER, PARAMETER:: BFFM_SETSTATUSTEXTW =(WM_USER + 104)
INTEGER, PARAMETER:: BFFM_SETSTATUSTEXT =BFFM_SETSTATUSTEXTA
INTEGER, PARAMETER:: BFFM_SETSELECTION =BFFM_SETSELECTIONA
INTEGER, PARAMETER:: BFFM_VALIDATEFAILED =BFFM_VALIDATEFAILEDA
INTERFACE
INTEGER FUNCTION SHGetPathFromIDLi
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
...continued here, since the previous message seems to have
exceeded some forum limit:
As for GetOpenFileName, no, strings cannot be of ALLOCATABLE length in F95. F2000 standard will allow for that, but we'll gona all wait quite a bit on that. You should parse the string manually -- the method I use is SCAN function. Docs on OPENFILENAME say that the last file name is terminated by double zero, so the code should be something like (written ad hoc, sorry if there are errors):
Regards
Jugoslav
exceeded some forum limit:
!================================================= INTEGER FUNCTION BrowseCallbackProc(hwnd, uMsg, lp, pData) !DEC$ATTRIBUTES STDCALL:: BrowseCallbackProc USE GLOBALS IMPLICIT NONE INTEGER:: hWnd, uMsg, lp, pData INTEGER:: iSt ! message from browser INTEGER, PARAMETER:: BFFM_INITIALIZED =1 INTEGER, PARAMETER:: BFFM_SELCHANGED =2 ! messages to browser INTEGER, PARAMETER:: BFFM_SETSTATUSTEXTA =(WM_USER + 100) INTEGER, PARAMETER:: BFFM_ENABLEOK =(WM_USER + 101) INTEGER, PARAMETER:: BFFM_SETSELECTIONA =(WM_USER + 102) INTEGER, PARAMETER:: BFFM_SETSELECTIONW =(WM_USER + 103) INTEGER, PARAMETER:: BFFM_SETSTATUSTEXTW =(WM_USER + 104) INTEGER, PARAMETER:: BFFM_SETSTATUSTEXT =BFFM_SETSTATUSTEXTA INTEGER, PARAMETER:: BFFM_SETSELECTION =BFFM_SETSELECTIONA INTEGER, PARAMETER:: BFFM_VALIDATEFAILED =BFFM_VALIDATEFAILEDA INTERFACE INTEGER FUNCTION SHGetPathFromIDList(lpIDList,szDir) !MS$ATTRIBUTES STDCALL,ALIAS: '_SHGetPathFromIDListA@8':: SHGetPathFromIDList !MS$ATTRIBUTES REFERENCE:: szDir INTEGER lpIDList CHARACTER*(*) szDir END FUNCTION END INTERFACE SELECT CASE(uMsg) CASE (BFFM_INITIALIZED) iSt=SendMessage(hwnd, BFFM_SETSELECTION, 1, LOC(szInitDir)) END SELECT BrowseCallbackProc=0 END FUNCTION BrowseCallbackProc
As for GetOpenFileName, no, strings cannot be of ALLOCATABLE length in F95. F2000 standard will allow for that, but we'll gona all wait quite a bit on that. You should parse the string manually -- the method I use is SCAN function. Docs on OPENFILENAME say that the last file name is terminated by double zero, so the code should be something like (written ad hoc, sorry if there are errors):
nBegin=1 !Beginning of new file nFiles=0 !Total no. of files DO i = 1, LEN(szFiles) !String to search nNextZero = SCAN( szFiles(nBegin:), CHAR(0) ) IF (nNextZero-nLastZero .LE. 1) EXIT !Terminal double zero sMyFile(i) = szFiles(nBegin:nNextZero-1) nFiles = nFiles + 1 nBegin = nNextZero + 1 END DO
Regards
Jugoslav
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi,
Just a note about SHBrowseForFolder. I didn't notice it in Jugoslav's post (I'm sure it's elsewhere in his code) but CoInitialize must be called before calling SHBrowseForFolder.
-John
PS - I like the hook procedure to select the initial directory. I think I'll add it to my code. ;-)
Just a note about SHBrowseForFolder. I didn't notice it in Jugoslav's post (I'm sure it's elsewhere in his code) but CoInitialize must be called before calling SHBrowseForFolder.
-John
PS - I like the hook procedure to select the initial directory. I think I'll add it to my code. ;-)
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi, Jugoslav. Thank you once more for the sample of SHBrowseForFolder.
I'll need time to try it and understand better.
Meanwhile I parsed the string of selected files by GetOpenFileName and constructed the system command like 'copy a.txt + b.txt temp.txt'. This command is located in a big string variable of length 8192.
Following compiler's recommendations I tried (instead of using SYSTEMQQ)
to create the file temp.txt with merged data, passing the part of string with command to the following subroutine containing CreateProcess function:
SUBROUTINE Do_exe(cmdline)
use dfwin
character(len=*), intent (in) :: cmdline
logical(4) :: lret
character, pointer :: AppName
type(T_STARTUPINFO) si
type(T_PROCESS_INFORMATION) pi
type(T_SECURITY_ATTRIBUTES), pointer :: sa
si%cb = 68 ; si%wShowWindow = SW_HIDE
NULLIFY(AppName)
lret = CreateProcess(AppName, cmdline, &
sa, sa, .FALSE., CREATE_SEPARATE_WOW_VDM, NULL, AppName, si, pi)
END SUBROUTINE Do_exe
It works well with EXE files but doesn't accept the string with system command. Is it possible to use CreateProcess to invoke DOS commands? If so, what am I doing wrong.
I very appreciate your help and don't want to bother at the same time. So it is my last question in this thread.
TIA, Andrei
okean@compuserve.com
I'll need time to try it and understand better.
Meanwhile I parsed the string of selected files by GetOpenFileName and constructed the system command like 'copy a.txt + b.txt temp.txt'. This command is located in a big string variable of length 8192.
Following compiler's recommendations I tried (instead of using SYSTEMQQ)
to create the file temp.txt with merged data, passing the part of string with command to the following subroutine containing CreateProcess function:
SUBROUTINE Do_exe(cmdline)
use dfwin
character(len=*), intent (in) :: cmdline
logical(4) :: lret
character, pointer :: AppName
type(T_STARTUPINFO) si
type(T_PROCESS_INFORMATION) pi
type(T_SECURITY_ATTRIBUTES), pointer :: sa
si%cb = 68 ; si%wShowWindow = SW_HIDE
NULLIFY(AppName)
lret = CreateProcess(AppName, cmdline, &
sa, sa, .FALSE., CREATE_SEPARATE_WOW_VDM, NULL, AppName, si, pi)
END SUBROUTINE Do_exe
It works well with EXE files but doesn't accept the string with system command. Is it possible to use CreateProcess to invoke DOS commands? If so, what am I doing wrong.
I very appreciate your help and don't want to bother at the same time. So it is my last question in this thread.
TIA, Andrei
okean@compuserve.com
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
You need to invoke the command interpreter when you use commands like copy. So, for example these would work as your commandline
'cmd /k copy a.txt + b.txt temp.txt'
'command /c copy a.txt + b.txt temp.txt'
I can't remember if Win9x supports cmd though, so choose you poison.
hth,
John
'cmd /k copy a.txt + b.txt temp.txt'
'command /c copy a.txt + b.txt temp.txt'
I can't remember if Win9x supports cmd though, so choose you poison.
hth,
John
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
SYSTEMQQ DFLIB function lets you do that without knowing what command interpreter is. If you prefer CreateProcess (which gives you finer control), name of command interpreter can be obtained by querying value of environment variable COMSPEC using GETENV, GETENVQQ or GetEnvironmentVariable.
Jugoslav
Jugoslav
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
> 'cmd /k copy a.txt + b.txt temp.txt'
> I can't remember if Win9x supports cmd ...
I tried it before and forgot to put /k (or better /c).
Yes, cmd is not supported by Win9*.
'command /c copy a.txt + b.txt temp.txt' doesn't work for me. On the other hand,
no problems with p.e. 'command /c dir > temp.txt'.
At last, I merged files simply opening and reading them in Fortran and
am asking myself, why haven't done it before.
Thank you John and Jugoslav,
Andrei
> I can't remember if Win9x supports cmd ...
I tried it before and forgot to put /k (or better /c).
Yes, cmd is not supported by Win9*.
'command /c copy a.txt + b.txt temp.txt' doesn't work for me. On the other hand,
no problems with p.e. 'command /c dir > temp.txt'.
At last, I merged files simply opening and reading them in Fortran and
am asking myself, why haven't done it before.
Thank you John and Jugoslav,
Andrei
Reply
Topic Options
- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page