Getting multiple files from GetOpenFileNameA

classic Classic list List threaded Threaded
13 messages Options
Reply | Threaded
Open this post in threaded view
|

Getting multiple files from GetOpenFileNameA

Zaaphod
This is the function I came up with to use GetOpenFileNameA() to get multiple files, and put the file names all into a StringList.

I think I am doing something fundamentally wrong here because I can run this in a loop sometimes 2 or 4 times, or sometimes 30 times, and it seems to work but eventually my program crashes with an access violation at various different points.. it's not always the same point in the program that crashes, but if I rig this to only build the stringlist once, I can run the rest of the process over and over including the GetOpenFileNameA() without issues.   I wonder if my method of putting the files names into the stringlist is flawed, I made it up myself based on what I could gather from the documentation of GetOpenFileNameA(),  maybe I am missing something.. or maybe the way I'm setting the string list to nil and then re-creating it is causing an issue?   The Writeln's I put in seem to be what I expect, but still it crashes at some point when I run this in a loop.   Below is my procedure, can anyone see anything I am doing in a bad way that would cause the instability I am experiencing?  

I am freeing the stringlist first thing, and I only create a new one if GetOpenFileNameA()is successful.  Then later on I check for the existence of the stringlist and if it's there, I process my files, the loop back and run this again, if not, I just exit, because if the string list does not exist then GetOpenFileNameA() was closed without selecting any files, so the process is complete.

Another issue with this....  I am only able to select 6 or 7 files with this and then GetOpenFileNameA() returns with False... I suspect I need to make a memory buffer for more files but don't know how to do that, anyone have any advice on how to fix that?


Procedure GetFilesIntoStringlist;
Begin
   IF (File_Stringlist<>Nil) Then
      FreeAndNil(File_Stringlist);
   fillchar(TFileName, sizeof(TFileName), 0);
   TFileName.lStructSize:=sizeof(TFileName);
   TFileName.hwndOwner:=0;
   TFileName.lpstrFile:=ret;
   TFileName.lpstrFile[0]:=#0;
   TFileName.nMaxFile:=100;
   TFileName.Flags := OFN_EXPLORER or OFN_FILEMUSTEXIST or OFN_ALLOWMULTISELECT;
   TFileName.lpstrDefExt:='';
   TFileName.lpstrTitle:='Production Automation Open Dpax File:';
   TFileName.lpstrFilter:='Draw.Pax Files (*.DPax)'+#0+'*.DPax'+#0;
   If Drawpaxfilename<>'' then
      Begin
         TFileName.lpstrFile:=Pchar(Drawpaxfilename+'DPax'+#0);
         TFileName.lpstrInitialDir:=Pchar(ExtractFilePath(Drawpaxfilename)+#0);
      End;
   OpenFileResult:=GetOpenFileNameA(@TFilename);
   If OpenFileResult then
      Begin
         Textcolor(10);
         IF File_Stringlist=Nil Then
            File_Stringlist:=TStringlist.Create;
         Loopx:=-1;
         filenum:=0;
         Repeat
            Filenamestr:='';
            Repeat
               Inc(Loopx);
               if TFileName.lpstrFile[loopx]<>#0 Then
                  begin
                     Write(TFileName.lpstrFile[loopx]);
                     Filenamestr:=Filenamestr+TFileName.lpstrFile[loopx];
                  end;
            Until TFileName.lpstrFile[loopx]=#0;
            Writeln;
            File_Stringlist.add(Filenamestr);
         Until TFileName.lpstrFile[loopx+1]=#0;
         Textcolor(14);
         If File_Stringlist.Count=1 then
            Writeln(File_Stringlist.Count,' File Selected')
         Else
            Writeln(File_Stringlist.Count-1,' Files Selected');
      End;
End;

James


_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: Getting multiple files from GetOpenFileNameA

Cyrax
On 21.5.2019 22.12, James Richters wrote:

> This is the function I came up with to use GetOpenFileNameA() to get multiple files, and put the file names all into a StringList.
>
> I think I am doing something fundamentally wrong here because I can run this in a loop sometimes 2 or 4 times, or sometimes 30 times, and it seems to work but eventually my program crashes with an access violation at various different points.. it's not always the same point in the program that crashes, but if I rig this to only build the stringlist once, I can run the rest of the process over and over including the GetOpenFileNameA() without issues.   I wonder if my method of putting the files names into the stringlist is flawed, I made it up myself based on what I could gather from the documentation of GetOpenFileNameA(),  maybe I am missing something.. or maybe the way I'm setting the string list to nil and then re-creating it is causing an issue?   The Writeln's I put in seem to be what I expect, but still it crashes at some point when I run this in a loop.   Below is my procedure, can anyone see anything I am doing in a bad way that would cause the instability I am experiencing?
>
> I am freeing the stringlist first thing, and I only create a new one if GetOpenFileNameA()is successful.  Then later on I check for the existence of the stringlist and if it's there, I process my files, the loop back and run this again, if not, I just exit, because if the string list does not exist then GetOpenFileNameA() was closed without selecting any files, so the process is complete.
>
> Another issue with this....  I am only able to select 6 or 7 files with this and then GetOpenFileNameA() returns with False... I suspect I need to make a memory buffer for more files but don't know how to do that, anyone have any advice on how to fix that?
>
>
> Procedure GetFilesIntoStringlist;
> Begin
>     IF (File_Stringlist<>Nil) Then
>        FreeAndNil(File_Stringlist);
>     fillchar(TFileName, sizeof(TFileName), 0);
>     TFileName.lStructSize:=sizeof(TFileName);
>     TFileName.hwndOwner:=0;
>     TFileName.lpstrFile:=ret;
>     TFileName.lpstrFile[0]:=#0;
>     TFileName.nMaxFile:=100;
>     TFileName.Flags := OFN_EXPLORER or OFN_FILEMUSTEXIST or OFN_ALLOWMULTISELECT;
>     TFileName.lpstrDefExt:='';
>     TFileName.lpstrTitle:='Production Automation Open Dpax File:';
>     TFileName.lpstrFilter:='Draw.Pax Files (*.DPax)'+#0+'*.DPax'+#0;
>     If Drawpaxfilename<>'' then
>        Begin
>           TFileName.lpstrFile:=Pchar(Drawpaxfilename+'DPax'+#0);
>           TFileName.lpstrInitialDir:=Pchar(ExtractFilePath(Drawpaxfilename)+#0);
>        End;
>     OpenFileResult:=GetOpenFileNameA(@TFilename);
>     If OpenFileResult then
>        Begin
>           Textcolor(10);
>           IF File_Stringlist=Nil Then
>              File_Stringlist:=TStringlist.Create;
>           Loopx:=-1;
>           filenum:=0;
>           Repeat
>              Filenamestr:='';
>              Repeat
>                 Inc(Loopx);
>                 if TFileName.lpstrFile[loopx]<>#0 Then
>                    begin
>                       Write(TFileName.lpstrFile[loopx]);
>                       Filenamestr:=Filenamestr+TFileName.lpstrFile[loopx];
>                    end;
>              Until TFileName.lpstrFile[loopx]=#0;
>              Writeln;
>              File_Stringlist.add(Filenamestr);
>           Until TFileName.lpstrFile[loopx+1]=#0;
>           Textcolor(14);
>           If File_Stringlist.Count=1 then
>              Writeln(File_Stringlist.Count,' File Selected')
>           Else
>              Writeln(File_Stringlist.Count-1,' Files Selected');
>        End;
> End;
>
> James
>
>
> _______________________________________________
> fpc-pascal maillist  -  [hidden email]
> http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
>

It looks like that you are using the type name directly (TFileName).
Where is TFileName defined?


_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: Getting multiple files from GetOpenFileNameA

Zaaphod
I have it defined with the program variables:

Here are all my Uses and Vars:

Uses
  ptcgraph,sysutils,Windows,Commdlg,Classes,CRT;

Var
TFilename              : TOpenFileNameA;
ret                    : array[0..100] of char;
OpenFileResult         : Boolean;
LoopX,filenum          : Longint;
filenamestr            : ansistring;
File_Stringlist        : tstringList;

The only examples of how to use GetOpenFilenameA I could find by searching were in C, so what I came up with is a combination of trying to translate C code to Pascal that I previously did to get GetSaveFilenameA to work and then a lof of just messing with it to try to get GetOpenFilenameA to work... I've used GetOpenFilenameA before, but only for very small programs that would have only asked for it once and then they would be done, and I didn't use OFN_AllowMultiSelect...  I got really confused by the examples on how to break out the contents .lpstrfile but by just reading the Microsoft document that said it was just the path then #0 then each file name followed by #0 with a double #0 at the end.. so I just made up something to extract the path and files and put them all in a much easier to manage tStringList

James

-----Original Message-----
From: fpc-pascal <[hidden email]> On Behalf Of Cyrax
Sent: Tuesday, May 21, 2019 4:55 PM
To: [hidden email]
Subject: Re: [fpc-pascal] Getting multiple files from GetOpenFileNameA

On 21.5.2019 22.12, James Richters wrote:

> This is the function I came up with to use GetOpenFileNameA() to get multiple files, and put the file names all into a StringList.
>
> I think I am doing something fundamentally wrong here because I can run this in a loop sometimes 2 or 4 times, or sometimes 30 times, and it seems to work but eventually my program crashes with an access violation at various different points.. it's not always the same point in the program that crashes, but if I rig this to only build the stringlist once, I can run the rest of the process over and over including the GetOpenFileNameA() without issues.   I wonder if my method of putting the files names into the stringlist is flawed, I made it up myself based on what I could gather from the documentation of GetOpenFileNameA(),  maybe I am missing something.. or maybe the way I'm setting the string list to nil and then re-creating it is causing an issue?   The Writeln's I put in seem to be what I expect, but still it crashes at some point when I run this in a loop.   Below is my procedure, can anyone see anything I am doing in a bad way that would cause the instability I am experiencing?
>
> I am freeing the stringlist first thing, and I only create a new one if GetOpenFileNameA()is successful.  Then later on I check for the existence of the stringlist and if it's there, I process my files, the loop back and run this again, if not, I just exit, because if the string list does not exist then GetOpenFileNameA() was closed without selecting any files, so the process is complete.
>
> Another issue with this....  I am only able to select 6 or 7 files with this and then GetOpenFileNameA() returns with False... I suspect I need to make a memory buffer for more files but don't know how to do that, anyone have any advice on how to fix that?
>
>
> Procedure GetFilesIntoStringlist;
> Begin
>     IF (File_Stringlist<>Nil) Then
>        FreeAndNil(File_Stringlist);
>     fillchar(TFileName, sizeof(TFileName), 0);
>     TFileName.lStructSize:=sizeof(TFileName);
>     TFileName.hwndOwner:=0;
>     TFileName.lpstrFile:=ret;
>     TFileName.lpstrFile[0]:=#0;
>     TFileName.nMaxFile:=100;
>     TFileName.Flags := OFN_EXPLORER or OFN_FILEMUSTEXIST or OFN_ALLOWMULTISELECT;
>     TFileName.lpstrDefExt:='';
>     TFileName.lpstrTitle:='Production Automation Open Dpax File:';
>     TFileName.lpstrFilter:='Draw.Pax Files (*.DPax)'+#0+'*.DPax'+#0;
>     If Drawpaxfilename<>'' then
>        Begin
>           TFileName.lpstrFile:=Pchar(Drawpaxfilename+'DPax'+#0);
>           TFileName.lpstrInitialDir:=Pchar(ExtractFilePath(Drawpaxfilename)+#0);
>        End;
>     OpenFileResult:=GetOpenFileNameA(@TFilename);
>     If OpenFileResult then
>        Begin
>           Textcolor(10);
>           IF File_Stringlist=Nil Then
>              File_Stringlist:=TStringlist.Create;
>           Loopx:=-1;
>           filenum:=0;
>           Repeat
>              Filenamestr:='';
>              Repeat
>                 Inc(Loopx);
>                 if TFileName.lpstrFile[loopx]<>#0 Then
>                    begin
>                       Write(TFileName.lpstrFile[loopx]);
>                       Filenamestr:=Filenamestr+TFileName.lpstrFile[loopx];
>                    end;
>              Until TFileName.lpstrFile[loopx]=#0;
>              Writeln;
>              File_Stringlist.add(Filenamestr);
>           Until TFileName.lpstrFile[loopx+1]=#0;
>           Textcolor(14);
>           If File_Stringlist.Count=1 then
>              Writeln(File_Stringlist.Count,' File Selected')
>           Else
>              Writeln(File_Stringlist.Count-1,' Files Selected');
>        End;
> End;
>
> James
>
>
> _______________________________________________
> fpc-pascal maillist  -  [hidden email]
> http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
>

It looks like that you are using the type name directly (TFileName).
Where is TFileName defined?


_______________________________________________
fpc-pascal maillist  -  [hidden email] http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: Getting multiple files from GetOpenFileNameA

Santiago A.
El 21/05/19 a las 23:17, James Richters escribió:

> I have it defined with the program variables:
>
> Here are all my Uses and Vars:
>
> Uses
>    ptcgraph,sysutils,Windows,Commdlg,Classes,CRT;
>
> Var
> TFilename              : TOpenFileNameA;
> ret                    : array[0..100] of char;
> OpenFileResult         : Boolean;
> LoopX,filenum          : Longint;
> filenamestr            : ansistring;
> File_Stringlist        : tstringList;

Are all those variables global unit scope?

Some points about design:
1) I think that file_StringList should be a parameter passed to the
function GetFilesIntoStringlist and created by the caller.
Procedure GetFilesIntoStringlist(var File_Stringlist:TStrings);

2) "TFilename" is a bad name for a variable. First, it is clashes with a
system type name. Second, starting it with "T" looks like a type name.
Rename to CurrentFileName, or OpenFileForWin, or something like that.

Try this way. Instead of adding each char to the string, that means
reallocating, use the standard function StrPas

           Loopx:=0;
           Repeat
              Filenamestr:=StrPas(@TFileName.lpstrFile[loopX]);
              Writeln(Filenamestr);
              File_Stringlist.add(Filenamestr);
              inc(Loopx,length(Filenamestr)+1);
           Until TFileName.lpstrFile[loopx]=#0;


Write the simplest project with this function that raises the error and
we can run and reproduce. Nevertheless, if you get random errors it is
some kind of memory error, probably overwrite in some place. It doesn't
look the problem is here.

--
Saludos

Santiago A.

_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: Getting multiple files from GetOpenFileNameA

Zaaphod
Thank you for the suggestions.     Yes the variables are all global.  The TFilename came from some C source that I had as an example.  I will take your recommendation and just make it a variable.   I guess strpas makes a string of all characters until it reaches a #0 ?    I'll give that a try.   I'll put together the simplest example that demonstrates the issue.  

-----Original Message-----
From: fpc-pascal <[hidden email]> On Behalf Of Santiago A.
Sent: Wednesday, May 22, 2019 12:56 PM
To: 'FPC-Pascal users discussions' <[hidden email]>
Subject: Re: [fpc-pascal] Getting multiple files from GetOpenFileNameA

El 21/05/19 a las 23:17, James Richters escribió:

> I have it defined with the program variables:
>
> Here are all my Uses and Vars:
>
> Uses
>    ptcgraph,sysutils,Windows,Commdlg,Classes,CRT;
>
> Var
> TFilename              : TOpenFileNameA;
> ret                    : array[0..100] of char;
> OpenFileResult         : Boolean;
> LoopX,filenum          : Longint;
> filenamestr            : ansistring;
> File_Stringlist        : tstringList;

Are all those variables global unit scope?

Some points about design:
1) I think that file_StringList should be a parameter passed to the function GetFilesIntoStringlist and created by the caller.
Procedure GetFilesIntoStringlist(var File_Stringlist:TStrings);

2) "TFilename" is a bad name for a variable. First, it is clashes with a system type name. Second, starting it with "T" looks like a type name.
Rename to CurrentFileName, or OpenFileForWin, or something like that.

Try this way. Instead of adding each char to the string, that means reallocating, use the standard function StrPas

           Loopx:=0;
           Repeat
              Filenamestr:=StrPas(@TFileName.lpstrFile[loopX]);
              Writeln(Filenamestr);
              File_Stringlist.add(Filenamestr);
              inc(Loopx,length(Filenamestr)+1);
           Until TFileName.lpstrFile[loopx]=#0;


Write the simplest project with this function that raises the error and we can run and reproduce. Nevertheless, if you get random errors it is some kind of memory error, probably overwrite in some place. It doesn't look the problem is here.

--
Saludos

Santiago A.

_______________________________________________
fpc-pascal maillist  -  [hidden email] http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: Getting multiple files from GetOpenFileNameA

Zaaphod

I have put together a program that demonstrates the issue I am having.  I have re-structured it a bit to try to make it more clear where the problem is.

While putting this together, I was able to get it to run fine with no problems if I did not try to put GetOpenFileNameA back to the directory of the last file I processed. Including a file sent in as a parameter.   If I set Open_File.lpstrFile:=Pchar(Target_File+#0+#0); where Target_File is the complete path and file name of the last file I processed,  If I select only one file, then the next time around it DOES work.. and will put me in the directory of Target_File and will show the filename of Target_File as a default, but if I select more than one file, the next time around, it crashes.. I have detailed the crash information in the sameple program comments.

Another way I wish to run this is to leave Open_File.lpstrFile alone and use Open_File.lpstrInitialDir to put me in the directory of the last processed file, but not specify a default filename.  I can’t get this to work correctly at all, but if I use Open_File.lpstrInitialDir without Open_File.lpstrFile then it does not crash,  I am just not put in the directory I expect to be in. 

 

Any Advice or suggestions on any of this, or on how I could improve the structure or methods of this program are greatly appreciated.

 

James

 

 

 

{$mode objfpc}{$H+}

//   https://docs.microsoft.com/en-us/windows/desktop/api/commdlg/nf-commdlg-getopenfilenamea

//   https://docs.microsoft.com/en-us/windows/desktop/api/commdlg/ns-commdlg-tagofna

Uses

  sysutils,Windows,Commdlg,Classes,CRT;

Var

Open_File          : TOpenFileNameA;

ret                : array[0..100000] of char;

Filenum            : Word;

Target_File        : AnsiString;

File_Stringlist    : tstringList;

{=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=}

Procedure Display_File_StringList(Var Display_String_List:tStringList);

Var

  SL_Loop : Word;

Begin

   If Display_String_List.Count=0 then

      Begin

         Textcolor(12);

         Writeln('0 Files Selected')

      End

   Else

   If Display_String_List.Count=1 then

      Begin

         TextColor(10);

         Writeln(Display_String_List[0]);

         Textcolor(14);

         Writeln('1 Files Selected');

      End

   Else

      Begin

         TextColor(13);

         Writeln('Path for all files: ',Display_String_List[0]);

         TextColor(10);

         For SL_Loop:= 1 to Display_String_List.Count-1 Do

            Writeln('File #',SL_Loop,': ',Display_String_List[SL_Loop]);

         Textcolor(14);

         Writeln(Display_String_List.Count-1,' Files Selected');

      End;

End;

{=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=}

Function Get_Files_Into_Stringlist(Var String_List:tStringList):Boolean;

Var

   Open_File_Result      : Boolean;

   Position_of_Filename  : Word;

Begin

   String_List.Clear;

   Open_File_Result:=GetOpenFileNameA(@Open_File);

   If Open_File_Result then

      Begin

         Position_of_Filename:=0;

         Repeat

            String_List.add(StrPas(@Open_File.lpstrFile[Position_of_Filename]));

            inc(Position_of_Filename,length(String_List[String_List.Count-1])+1);

         Until Open_File.lpstrFile[Position_of_Filename]=#0;

      End;

   Writeln(Open_File_Result);

   Get_Files_Into_Stringlist:=Open_File_Result;

End;

{=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=}

Procedure Process_File(Some_File: AnsiString);

Begin

   TextColor(11);

   Writeln('Processing File: ',Some_File);

End;

{=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=}

Begin {Main Program}

   fillchar(Open_File, sizeof(Open_File), 0);

   fillchar(ret, sizeof(ret), 0);

   Open_File.lStructSize:=sizeof(Open_File);

   Open_File.hwndOwner:=0;

   Open_File.lpstrFile:=ret;

   Open_File.lpstrFile[0]:=#0;

   Open_File.nMaxFile:=100000;

   Open_File.Flags := OFN_EXPLORER or OFN_FILEMUSTEXIST or OFN_ALLOWMULTISELECT;

   Open_File.lpstrDefExt:='.txt';

   Open_File.lpstrTitle:='My Program - Open File';

   Open_File.lpstrFilter:='All Files (*.*)'+#0+'*.*'+#0;

   File_Stringlist:=TStringlist.Create;

   If paramstr(1)<>'' then

      Begin

         Target_File:=paramstr(1);

         Process_File(Target_File);

      End

   else

      Target_File:='';

   Repeat

      If Target_File<>'' then

         Begin

            // The following line seems to cause my program to crash.

            // It does seem to work as I expect.  It puts me in the directory

            // of the file and shows the file name, but for some reason if I select

            // more than one file than I get

            // An unhandled exception occurred at $0040B428:

            // EAccessViolation:

            // $0040B428

            // $0040A03D

            // $00414447

            // $0040AE1E

            // $0040A03D

            // $00414447

            // $0040AE1E

            // $0040A03D

            // $00414447

            // $0040AE1E

            // $0040A03D

            // $00414447

            // $0040AE1E

            // $0040A03D

            // $00414447

            // $0040AE1E

            // $0040A03D

            // in a repeating loop if I use the command with two #0 at the end of

            // Open_File.lpstrFile:=Pchar(Target_File+#0+#0);

           

            // Or I get:

            // EAccessViolation: An unhandled exception occurred at $0040BB56:

            // with an exit code of 253

            // or

            // An unhandled exception occurred at $0040BDD2:

            // EAccessViolation: Access violation

            // $0040BDD2

            // with an exit with a code 217

            // if I use one #0 at the end of

            // Open_File.lpstrFile:=Pchar(Target_File+#0);

           

            // these errors seem to show up more if I select multiple files or

            // change directories. 

            Open_File.lpstrFile:=Pchar(Target_File+#0);

           

            

            // If I leaved the above commented out, then I should be able to use the

            // command below to just put me in the directory specified, but with no default file

            // This does not work the way I expect it to work at all.

            // It does not put me into the directory of the file used as a parameter, it

            // Then for other files it puts me one level before the one I was just in

            // I want to be back where I was.  If I give it a parameter, I want to

            // be in the directory of the file the parameter specifies, and then

            // I want to be in the directory of the previous file.

            // This just is not working the way I expect but does not cause any crash.

            Open_File.lpstrInitialDir:=Pchar(ExtractFilePath(Target_File)+#0+#0);

         End;

      Get_Files_Into_Stringlist(File_Stringlist);

      Display_File_StringList(File_Stringlist);

      If (File_Stringlist.Count=1) and FileExists(File_Stringlist[0]) Then

         Begin

            Target_File:=File_Stringlist[0];

            Process_File(Target_File);

         End

      Else

      If (File_Stringlist.Count>1) Then

         Begin

            Filenum:=0;

            Repeat

               Inc(Filenum);

               If (Filenum<File_Stringlist.Count) Then

                  Begin

                     Target_File:=File_Stringlist[0];

                     If Target_File[Length(Target_File)]<>'\' Then

                        Target_File:=Target_File+'\';

                     Target_File:=Target_File+File_Stringlist[Filenum];

                     Process_File(Target_File);

                  End;

            Until Filenum>=File_Stringlist.Count;

         End;

   Until File_Stringlist.count=0;

   File_Stringlist.Free;

end.

{=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=}


_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal

Getfilenamea to Stringlist.pas (7K) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Getting multiple files from GetOpenFileNameA

Luis - SoftSAT Sistemas
Try replacing
// these errors seem to show up more if I select multiple files or 
// change directories.  
Open_File.lpstrFile:=Pchar(Target_File+#0);
with something like
Move(Target_File, Open_File.lpstrFile, Length(Target_File) + 1);
 

_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: Getting multiple files from GetOpenFileNameA

Alexander Grotewohl
In reply to this post by Zaaphod
I did notice lpstrFilter is terminated by one #0 instead of two. Other than that not at a pc to test.

--
Alexander Grotewohl
http://dcclost.com

On May 23, 2019 7:52 AM, James Richters <[hidden email]> wrote:

I have put together a program that demonstrates the issue I am having.  I have re-structured it a bit to try to make it more clear where the problem is.

While putting this together, I was able to get it to run fine with no problems if I did not try to put GetOpenFileNameA back to the directory of the last file I processed. Including a file sent in as a parameter.   If I set Open_File.lpstrFile:=Pchar(Target_File+#0+#0); where Target_File is the complete path and file name of the last file I processed,  If I select only one file, then the next time around it DOES work.. and will put me in the directory of Target_File and will show the filename of Target_File as a default, but if I select more than one file, the next time around, it crashes.. I have detailed the crash information in the sameple program comments.

Another way I wish to run this is to leave Open_File.lpstrFile alone and use Open_File.lpstrInitialDir to put me in the directory of the last processed file, but not specify a default filename.  I can’t get this to work correctly at all, but if I use Open_File.lpstrInitialDir without Open_File.lpstrFile then it does not crash,  I am just not put in the directory I expect to be in. 

 

Any Advice or suggestions on any of this, or on how I could improve the structure or methods of this program are greatly appreciated.

 

James

 

 

 

{$mode objfpc}{$H+}

//   https://docs.microsoft.com/en-us/windows/desktop/api/commdlg/nf-commdlg-getopenfilenamea

//   https://docs.microsoft.com/en-us/windows/desktop/api/commdlg/ns-commdlg-tagofna

Uses

  sysutils,Windows,Commdlg,Classes,CRT;

Var

Open_File          : TOpenFileNameA;

ret                : array[0..100000] of char;

Filenum            : Word;

Target_File        : AnsiString;

File_Stringlist    : tstringList;

{=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=}

Procedure Display_File_StringList(Var Display_String_List:tStringList);

Var

  SL_Loop : Word;

Begin

   If Display_String_List.Count=0 then

      Begin

         Textcolor(12);

         Writeln('0 Files Selected')

      End

   Else

   If Display_String_List.Count=1 then

      Begin

         TextColor(10);

         Writeln(Display_String_List[0]);

         Textcolor(14);

         Writeln('1 Files Selected');

      End

   Else

      Begin

         TextColor(13);

         Writeln('Path for all files: ',Display_String_List[0]);

         TextColor(10);

         For SL_Loop:= 1 to Display_String_List.Count-1 Do

            Writeln('File #',SL_Loop,': ',Display_String_List[SL_Loop]);

         Textcolor(14);

         Writeln(Display_String_List.Count-1,' Files Selected');

      End;

End;

{=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=}

Function Get_Files_Into_Stringlist(Var String_List:tStringList):Boolean;

Var

   Open_File_Result      : Boolean;

   Position_of_Filename  : Word;

Begin

   String_List.Clear;

   Open_File_Result:=GetOpenFileNameA(@Open_File);

   If Open_File_Result then

      Begin

         Position_of_Filename:=0;

         Repeat

            String_List.add(StrPas(@Open_File.lpstrFile[Position_of_Filename]));

            inc(Position_of_Filename,length(String_List[String_List.Count-1])+1);

         Until Open_File.lpstrFile[Position_of_Filename]=#0;

      End;

   Writeln(Open_File_Result);

   Get_Files_Into_Stringlist:=Open_File_Result;

End;

{=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=}

Procedure Process_File(Some_File: AnsiString);

Begin

   TextColor(11);

   Writeln('Processing File: ',Some_File);

End;

{=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=}

Begin {Main Program}

   fillchar(Open_File, sizeof(Open_File), 0);

   fillchar(ret, sizeof(ret), 0);

   Open_File.lStructSize:=sizeof(Open_File);

   Open_File.hwndOwner:=0;

   Open_File.lpstrFile:=ret;

   Open_File.lpstrFile[0]:=#0;

   Open_File.nMaxFile:=100000;

   Open_File.Flags := OFN_EXPLORER or OFN_FILEMUSTEXIST or OFN_ALLOWMULTISELECT;

   Open_File.lpstrDefExt:='.txt';

   Open_File.lpstrTitle:='My Program - Open File';

   Open_File.lpstrFilter:='All Files (*.*)'+#0+'*.*'+#0;

   File_Stringlist:=TStringlist.Create;

   If paramstr(1)<>'' then

      Begin

         Target_File:=paramstr(1);

         Process_File(Target_File);

      End

   else

      Target_File:='';

   Repeat

      If Target_File<>'' then

         Begin

            // The following line seems to cause my program to crash.

            // It does seem to work as I expect.  It puts me in the directory

            // of the file and shows the file name, but for some reason if I select

            // more than one file than I get

            // An unhandled exception occurred at $0040B428:

            // EAccessViolation:

            // $0040B428

            // $0040A03D

            // $00414447

            // $0040AE1E

            // $0040A03D

            // $00414447

            // $0040AE1E

            // $0040A03D

            // $00414447

            // $0040AE1E

            // $0040A03D

            // $00414447

            // $0040AE1E

            // $0040A03D

            // $00414447

            // $0040AE1E

            // $0040A03D

            // in a repeating loop if I use the command with two #0 at the end of

            // Open_File.lpstrFile:=Pchar(Target_File+#0+#0);

           

            // Or I get:

            // EAccessViolation: An unhandled exception occurred at $0040BB56:

            // with an exit code of 253

            // or

            // An unhandled exception occurred at $0040BDD2:

            // EAccessViolation: Access violation

            // $0040BDD2

            // with an exit with a code 217

            // if I use one #0 at the end of

            // Open_File.lpstrFile:=Pchar(Target_File+#0);

           

            // these errors seem to show up more if I select multiple files or

            // change directories. 

            Open_File.lpstrFile:=Pchar(Target_File+#0);

           

            

            // If I leaved the above commented out, then I should be able to use the

            // command below to just put me in the directory specified, but with no default file

            // This does not work the way I expect it to work at all.

            // It does not put me into the directory of the file used as a parameter, it

            // Then for other files it puts me one level before the one I was just in

            // I want to be back where I was.  If I give it a parameter, I want to

            // be in the directory of the file the parameter specifies, and then

            // I want to be in the directory of the previous file.

            // This just is not working the way I expect but does not cause any crash.

            Open_File.lpstrInitialDir:=Pchar(ExtractFilePath(Target_File)+#0+#0);

         End;

      Get_Files_Into_Stringlist(File_Stringlist);

      Display_File_StringList(File_Stringlist);

      If (File_Stringlist.Count=1) and FileExists(File_Stringlist[0]) Then

         Begin

            Target_File:=File_Stringlist[0];

            Process_File(Target_File);

         End

      Else

      If (File_Stringlist.Count>1) Then

         Begin

            Filenum:=0;

            Repeat

               Inc(Filenum);

               If (Filenum<File_Stringlist.Count) Then

                  Begin

                     Target_File:=File_Stringlist[0];

                     If Target_File[Length(Target_File)]<>'\' Then

                        Target_File:=Target_File+'\';

                     Target_File:=Target_File+File_Stringlist[Filenum];

                     Process_File(Target_File);

                  End;

            Until Filenum>=File_Stringlist.Count;

         End;

   Until File_Stringlist.count=0;

   File_Stringlist.Free;

end.

{=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=}



_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: Getting multiple files from GetOpenFileNameA

Zaaphod

I’m not clear about when they need one #0 or two.  I thought it was just .lpstrFile to make it clear there weren’t more file names in it.. so one #0 between each name and double #0 at the end.. maybe they all need double #0 at the end?

 

James

 

From: fpc-pascal <[hidden email]> On Behalf Of Alexander Grotewohl
Sent: Thursday, May 23, 2019 11:56 AM
To: FPC-Pascal users discussions <[hidden email]>
Subject: Re: [fpc-pascal] Getting multiple files from GetOpenFileNameA

 

I did notice lpstrFilter is terminated by one #0 instead of two. Other than that not at a pc to test.

--
Alexander Grotewohl
http://dcclost.com

 

On May 23, 2019 7:52 AM, James Richters <[hidden email]> wrote:

I have put together a program that demonstrates the issue I am having.  I have re-structured it a bit to try to make it more clear where the problem is.

While putting this together, I was able to get it to run fine with no problems if I did not try to put GetOpenFileNameA back to the directory of the last file I processed. Including a file sent in as a parameter.   If I set Open_File.lpstrFile:=Pchar(Target_File+#0+#0); where Target_File is the complete path and file name of the last file I processed,  If I select only one file, then the next time around it DOES work.. and will put me in the directory of Target_File and will show the filename of Target_File as a default, but if I select more than one file, the next time around, it crashes.. I have detailed the crash information in the sameple program comments.

Another way I wish to run this is to leave Open_File.lpstrFile alone and use Open_File.lpstrInitialDir to put me in the directory of the last processed file, but not specify a default filename.  I can’t get this to work correctly at all, but if I use Open_File.lpstrInitialDir without Open_File.lpstrFile then it does not crash,  I am just not put in the directory I expect to be in. 

 

Any Advice or suggestions on any of this, or on how I could improve the structure or methods of this program are greatly appreciated.

 

James

 

 

 

{$mode objfpc}{$H+}

//   https://docs.microsoft.com/en-us/windows/desktop/api/commdlg/nf-commdlg-getopenfilenamea

//   https://docs.microsoft.com/en-us/windows/desktop/api/commdlg/ns-commdlg-tagofna

Uses

  sysutils,Windows,Commdlg,Classes,CRT;

Var

Open_File          : TOpenFileNameA;

ret                : array[0..100000] of char;

Filenum            : Word;

Target_File        : AnsiString;

File_Stringlist    : tstringList;

{=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=}

Procedure Display_File_StringList(Var Display_String_List:tStringList);

Var

  SL_Loop : Word;

Begin

   If Display_String_List.Count=0 then

      Begin

         Textcolor(12);

         Writeln('0 Files Selected')

      End

   Else

   If Display_String_List.Count=1 then

      Begin

         TextColor(10);

         Writeln(Display_String_List[0]);

         Textcolor(14);

         Writeln('1 Files Selected');

      End

   Else

      Begin

         TextColor(13);

         Writeln('Path for all files: ',Display_String_List[0]);

         TextColor(10);

         For SL_Loop:= 1 to Display_String_List.Count-1 Do

            Writeln('File #',SL_Loop,': ',Display_String_List[SL_Loop]);

         Textcolor(14);

         Writeln(Display_String_List.Count-1,' Files Selected');

      End;

End;

{=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=}

Function Get_Files_Into_Stringlist(Var String_List:tStringList):Boolean;

Var

   Open_File_Result      : Boolean;

   Position_of_Filename  : Word;

Begin

   String_List.Clear;

   Open_File_Result:=GetOpenFileNameA(@Open_File);

   If Open_File_Result then

      Begin

         Position_of_Filename:=0;

         Repeat

            String_List.add(StrPas(@Open_File.lpstrFile[Position_of_Filename]));

            inc(Position_of_Filename,length(String_List[String_List.Count-1])+1);

         Until Open_File.lpstrFile[Position_of_Filename]=#0;

      End;

   Writeln(Open_File_Result);

   Get_Files_Into_Stringlist:=Open_File_Result;

End;

{=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=}

Procedure Process_File(Some_File: AnsiString);

Begin

   TextColor(11);

   Writeln('Processing File: ',Some_File);

End;

{=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=}

Begin {Main Program}

   fillchar(Open_File, sizeof(Open_File), 0);

   fillchar(ret, sizeof(ret), 0);

   Open_File.lStructSize:=sizeof(Open_File);

   Open_File.hwndOwner:=0;

   Open_File.lpstrFile:=ret;

   Open_File.lpstrFile[0]:=#0;

   Open_File.nMaxFile:=100000;

   Open_File.Flags := OFN_EXPLORER or OFN_FILEMUSTEXIST or OFN_ALLOWMULTISELECT;

   Open_File.lpstrDefExt:='.txt';

   Open_File.lpstrTitle:='My Program - Open File';

   Open_File.lpstrFilter:='All Files (*.*)'+#0+'*.*'+#0;

   File_Stringlist:=TStringlist.Create;

   If paramstr(1)<>'' then

      Begin

         Target_File:=paramstr(1);

         Process_File(Target_File);

      End

   else

      Target_File:='';

   Repeat

      If Target_File<>'' then

         Begin

            // The following line seems to cause my program to crash.

            // It does seem to work as I expect.  It puts me in the directory

            // of the file and shows the file name, but for some reason if I select

            // more than one file than I get

            // An unhandled exception occurred at $0040B428:

            // EAccessViolation:

            // $0040B428

            // $0040A03D

            // $00414447

            // $0040AE1E

            // $0040A03D

            // $00414447

            // $0040AE1E

            // $0040A03D

            // $00414447

            // $0040AE1E

            // $0040A03D

            // $00414447

            // $0040AE1E

            // $0040A03D

            // $00414447

            // $0040AE1E

            // $0040A03D

            // in a repeating loop if I use the command with two #0 at the end of

            // Open_File.lpstrFile:=Pchar(Target_File+#0+#0);

           

            // Or I get:

            // EAccessViolation: An unhandled exception occurred at $0040BB56:

            // with an exit code of 253

            // or

            // An unhandled exception occurred at $0040BDD2:

            // EAccessViolation: Access violation

            // $0040BDD2

            // with an exit with a code 217

            // if I use one #0 at the end of

            // Open_File.lpstrFile:=Pchar(Target_File+#0);

           

            // these errors seem to show up more if I select multiple files or

            // change directories. 

            Open_File.lpstrFile:=Pchar(Target_File+#0);

           

            

            // If I leaved the above commented out, then I should be able to use the

            // command below to just put me in the directory specified, but with no default file

            // This does not work the way I expect it to work at all.

            // It does not put me into the directory of the file used as a parameter, it

            // Then for other files it puts me one level before the one I was just in

            // I want to be back where I was.  If I give it a parameter, I want to

            // be in the directory of the file the parameter specifies, and then

            // I want to be in the directory of the previous file.

            // This just is not working the way I expect but does not cause any crash.

            Open_File.lpstrInitialDir:=Pchar(ExtractFilePath(Target_File)+#0+#0);

         End;

      Get_Files_Into_Stringlist(File_Stringlist);

      Display_File_StringList(File_Stringlist);

      If (File_Stringlist.Count=1) and FileExists(File_Stringlist[0]) Then

         Begin

            Target_File:=File_Stringlist[0];

            Process_File(Target_File);

         End

      Else

      If (File_Stringlist.Count>1) Then

         Begin

            Filenum:=0;

            Repeat

               Inc(Filenum);

               If (Filenum<File_Stringlist.Count) Then

                  Begin

                     Target_File:=File_Stringlist[0];

                     If Target_File[Length(Target_File)]<>'\' Then

                        Target_File:=Target_File+'\';

                     Target_File:=Target_File+File_Stringlist[Filenum];

                     Process_File(Target_File);

                  End;

            Until Filenum>=File_Stringlist.Count;

         End;

   Until File_Stringlist.count=0;

   File_Stringlist.Free;

end.

{=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=}

 


_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: Getting multiple files from GetOpenFileNameA

Alexander Grotewohl
The whole structure is documented here

https://docs.microsoft.com/en-us/windows/desktop/api/commdlg/ns-commdlg-tagofna

I just read through it and noticed that. My guess is anything that takes multiple strings that way.



--
Alexander Grotewohl
http://dcclost.com

On May 23, 2019 12:09 PM, James Richters <[hidden email]> wrote:

I’m not clear about when they need one #0 or two.  I thought it was just .lpstrFile to make it clear there weren’t more file names in it.. so one #0 between each name and double #0 at the end.. maybe they all need double #0 at the end?

 

James

 

From: fpc-pascal <fpc-pascal-bounces@lists.freepascal.org> On Behalf Of Alexander Grotewohl
Sent: Thursday, May 23, 2019 11:56 AM
To: FPC-Pascal users discussions <fpc-pascal@lists.freepascal.org>
Subject: Re: [fpc-pascal] Getting multiple files from GetOpenFileNameA

 

I did notice lpstrFilter is terminated by one #0 instead of two. Other than that not at a pc to test.

--
Alexander Grotewohl
http://dcclost.com

 

On May 23, 2019 7:52 AM, James Richters <[hidden email]> wrote:

I have put together a program that demonstrates the issue I am having.  I have re-structured it a bit to try to make it more clear where the problem is.

While putting this together, I was able to get it to run fine with no problems if I did not try to put GetOpenFileNameA back to the directory of the last file I processed. Including a file sent in as a parameter.   If I set Open_File.lpstrFile:=Pchar(Target_File+#0+#0); where Target_File is the complete path and file name of the last file I processed,  If I select only one file, then the next time around it DOES work.. and will put me in the directory of Target_File and will show the filename of Target_File as a default, but if I select more than one file, the next time around, it crashes.. I have detailed the crash information in the sameple program comments.

Another way I wish to run this is to leave Open_File.lpstrFile alone and use Open_File.lpstrInitialDir to put me in the directory of the last processed file, but not specify a default filename.  I can’t get this to work correctly at all, but if I use Open_File.lpstrInitialDir without Open_File.lpstrFile then it does not crash,  I am just not put in the directory I expect to be in. 

 

Any Advice or suggestions on any of this, or on how I could improve the structure or methods of this program are greatly appreciated.

 

James

 

 

 

{$mode objfpc}{$H+}

//   https://docs.microsoft.com/en-us/windows/desktop/api/commdlg/nf-commdlg-getopenfilenamea

//   https://docs.microsoft.com/en-us/windows/desktop/api/commdlg/ns-commdlg-tagofna

Uses

  sysutils,Windows,Commdlg,Classes,CRT;

Var

Open_File          : TOpenFileNameA;

ret                : array[0..100000] of char;

Filenum            : Word;

Target_File        : AnsiString;

File_Stringlist    : tstringList;

{=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=}

Procedure Display_File_StringList(Var Display_String_List:tStringList);

Var

  SL_Loop : Word;

Begin

   If Display_String_List.Count=0 then

      Begin

         Textcolor(12);

         Writeln('0 Files Selected')

      End

   Else

   If Display_String_List.Count=1 then

      Begin

         TextColor(10);

         Writeln(Display_String_List[0]);

         Textcolor(14);

         Writeln('1 Files Selected');

      End

   Else

      Begin

         TextColor(13);

         Writeln('Path for all files: ',Display_String_List[0]);

         TextColor(10);

         For SL_Loop:= 1 to Display_String_List.Count-1 Do

            Writeln('File #',SL_Loop,': ',Display_String_List[SL_Loop]);

         Textcolor(14);

         Writeln(Display_String_List.Count-1,' Files Selected');

      End;

End;

{=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=}

Function Get_Files_Into_Stringlist(Var String_List:tStringList):Boolean;

Var

   Open_File_Result      : Boolean;

   Position_of_Filename  : Word;

Begin

   String_List.Clear;

   Open_File_Result:=GetOpenFileNameA(@Open_File);

   If Open_File_Result then

      Begin

         Position_of_Filename:=0;

         Repeat

            String_List.add(StrPas(@Open_File.lpstrFile[Position_of_Filename]));

            inc(Position_of_Filename,length(String_List[String_List.Count-1])+1);

         Until Open_File.lpstrFile[Position_of_Filename]=#0;

      End;

   Writeln(Open_File_Result);

   Get_Files_Into_Stringlist:=Open_File_Result;

End;

{=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=}

Procedure Process_File(Some_File: AnsiString);

Begin

   TextColor(11);

   Writeln('Processing File: ',Some_File);

End;

{=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=}

Begin {Main Program}

   fillchar(Open_File, sizeof(Open_File), 0);

   fillchar(ret, sizeof(ret), 0);

   Open_File.lStructSize:=sizeof(Open_File);

   Open_File.hwndOwner:=0;

   Open_File.lpstrFile:=ret;

   Open_File.lpstrFile[0]:=#0;

   Open_File.nMaxFile:=100000;

   Open_File.Flags := OFN_EXPLORER or OFN_FILEMUSTEXIST or OFN_ALLOWMULTISELECT;

   Open_File.lpstrDefExt:='.txt';

   Open_File.lpstrTitle:='My Program - Open File';

   Open_File.lpstrFilter:='All Files (*.*)'+#0+'*.*'+#0;

   File_Stringlist:=TStringlist.Create;

   If paramstr(1)<>'' then

      Begin

         Target_File:=paramstr(1);

         Process_File(Target_File);

      End

   else

      Target_File:='';

   Repeat

      If Target_File<>'' then

         Begin

            // The following line seems to cause my program to crash.

            // It does seem to work as I expect.  It puts me in the directory

            // of the file and shows the file name, but for some reason if I select

            // more than one file than I get

            // An unhandled exception occurred at $0040B428:

            // EAccessViolation:

            // $0040B428

            // $0040A03D

            // $00414447

            // $0040AE1E

            // $0040A03D

            // $00414447

            // $0040AE1E

            // $0040A03D

            // $00414447

            // $0040AE1E

            // $0040A03D

            // $00414447

            // $0040AE1E

            // $0040A03D

            // $00414447

            // $0040AE1E

            // $0040A03D

            // in a repeating loop if I use the command with two #0 at the end of

            // Open_File.lpstrFile:=Pchar(Target_File+#0+#0);

           

            // Or I get:

            // EAccessViolation: An unhandled exception occurred at $0040BB56:

            // with an exit code of 253

            // or

            // An unhandled exception occurred at $0040BDD2:

            // EAccessViolation: Access violation

            // $0040BDD2

            // with an exit with a code 217

            // if I use one #0 at the end of

            // Open_File.lpstrFile:=Pchar(Target_File+#0);

           

            // these errors seem to show up more if I select multiple files or

            // change directories. 

            Open_File.lpstrFile:=Pchar(Target_File+#0);

           

            

            // If I leaved the above commented out, then I should be able to use the

            // command below to just put me in the directory specified, but with no default file

            // This does not work the way I expect it to work at all.

            // It does not put me into the directory of the file used as a parameter, it

            // Then for other files it puts me one level before the one I was just in

            // I want to be back where I was.  If I give it a parameter, I want to

            // be in the directory of the file the parameter specifies, and then

            // I want to be in the directory of the previous file.

            // This just is not working the way I expect but does not cause any crash.

            Open_File.lpstrInitialDir:=Pchar(ExtractFilePath(Target_File)+#0+#0);

         End;

      Get_Files_Into_Stringlist(File_Stringlist);

      Display_File_StringList(File_Stringlist);

      If (File_Stringlist.Count=1) and FileExists(File_Stringlist[0]) Then

         Begin

            Target_File:=File_Stringlist[0];

            Process_File(Target_File);

         End

      Else

      If (File_Stringlist.Count>1) Then

         Begin

            Filenum:=0;

            Repeat

               Inc(Filenum);

               If (Filenum<File_Stringlist.Count) Then

                  Begin

                     Target_File:=File_Stringlist[0];

                     If Target_File[Length(Target_File)]<>'\' Then

                        Target_File:=Target_File+'\';

                     Target_File:=Target_File+File_Stringlist[Filenum];

                     Process_File(Target_File);

                  End;

            Until Filenum>=File_Stringlist.Count;

         End;

   Until File_Stringlist.count=0;

   File_Stringlist.Free;

end.

{=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=}

 



_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: Getting multiple files from GetOpenFileNameA

Zaaphod

Oh that makes sense… so it would know when there wasn’t another string.  I’ll put another #0 that seems to be the correct way.

 

James

From: fpc-pascal <[hidden email]> On Behalf Of Alexander Grotewohl
Sent: Thursday, May 23, 2019 12:22 PM
To: FPC-Pascal users discussions <[hidden email]>
Subject: Re: [fpc-pascal] Getting multiple files from GetOpenFileNameA

 

The whole structure is documented here

 

 

I just read through it and noticed that. My guess is anything that takes multiple strings that way.

 

 

--
Alexander Grotewohl
http://dcclost.com

 

On May 23, 2019 12:09 PM, James Richters <[hidden email]> wrote:

I’m not clear about when they need one #0 or two.  I thought it was just .lpstrFile to make it clear there weren’t more file names in it.. so one #0 between each name and double #0 at the end.. maybe they all need double #0 at the end?

 

James

 

From: fpc-pascal <[hidden email]> On Behalf Of Alexander Grotewohl
Sent: Thursday, May 23, 2019 11:56 AM
To: FPC-Pascal users discussions <[hidden email]>
Subject: Re: [fpc-pascal] Getting multiple files from GetOpenFileNameA

 

I did notice lpstrFilter is terminated by one #0 instead of two. Other than that not at a pc to test.

--
Alexander Grotewohl
http://dcclost.com

 

On May 23, 2019 7:52 AM, James Richters <[hidden email]> wrote:

I have put together a program that demonstrates the issue I am having.  I have re-structured it a bit to try to make it more clear where the problem is.

While putting this together, I was able to get it to run fine with no problems if I did not try to put GetOpenFileNameA back to the directory of the last file I processed. Including a file sent in as a parameter.   If I set Open_File.lpstrFile:=Pchar(Target_File+#0+#0); where Target_File is the complete path and file name of the last file I processed,  If I select only one file, then the next time around it DOES work.. and will put me in the directory of Target_File and will show the filename of Target_File as a default, but if I select more than one file, the next time around, it crashes.. I have detailed the crash information in the sameple program comments.

Another way I wish to run this is to leave Open_File.lpstrFile alone and use Open_File.lpstrInitialDir to put me in the directory of the last processed file, but not specify a default filename.  I can’t get this to work correctly at all, but if I use Open_File.lpstrInitialDir without Open_File.lpstrFile then it does not crash,  I am just not put in the directory I expect to be in. 

 

Any Advice or suggestions on any of this, or on how I could improve the structure or methods of this program are greatly appreciated.

 

James

 

 

 

{$mode objfpc}{$H+}

//   https://docs.microsoft.com/en-us/windows/desktop/api/commdlg/nf-commdlg-getopenfilenamea

//   https://docs.microsoft.com/en-us/windows/desktop/api/commdlg/ns-commdlg-tagofna

Uses

  sysutils,Windows,Commdlg,Classes,CRT;

Var

Open_File          : TOpenFileNameA;

ret                : array[0..100000] of char;

Filenum            : Word;

Target_File        : AnsiString;

File_Stringlist    : tstringList;

{=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=}

Procedure Display_File_StringList(Var Display_String_List:tStringList);

Var

  SL_Loop : Word;

Begin

   If Display_String_List.Count=0 then

      Begin

         Textcolor(12);

         Writeln('0 Files Selected')

      End

   Else

   If Display_String_List.Count=1 then

      Begin

         TextColor(10);

         Writeln(Display_String_List[0]);

         Textcolor(14);

         Writeln('1 Files Selected');

      End

   Else

      Begin

         TextColor(13);

         Writeln('Path for all files: ',Display_String_List[0]);

         TextColor(10);

         For SL_Loop:= 1 to Display_String_List.Count-1 Do

            Writeln('File #',SL_Loop,': ',Display_String_List[SL_Loop]);

         Textcolor(14);

         Writeln(Display_String_List.Count-1,' Files Selected');

      End;

End;

{=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=}

Function Get_Files_Into_Stringlist(Var String_List:tStringList):Boolean;

Var

   Open_File_Result      : Boolean;

   Position_of_Filename  : Word;

Begin

   String_List.Clear;

   Open_File_Result:=GetOpenFileNameA(@Open_File);

   If Open_File_Result then

      Begin

         Position_of_Filename:=0;

         Repeat

            String_List.add(StrPas(@Open_File.lpstrFile[Position_of_Filename]));

            inc(Position_of_Filename,length(String_List[String_List.Count-1])+1);

         Until Open_File.lpstrFile[Position_of_Filename]=#0;

      End;

   Writeln(Open_File_Result);

   Get_Files_Into_Stringlist:=Open_File_Result;

End;

{=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=}

Procedure Process_File(Some_File: AnsiString);

Begin

   TextColor(11);

   Writeln('Processing File: ',Some_File);

End;

{=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=}

Begin {Main Program}

   fillchar(Open_File, sizeof(Open_File), 0);

   fillchar(ret, sizeof(ret), 0);

   Open_File.lStructSize:=sizeof(Open_File);

   Open_File.hwndOwner:=0;

   Open_File.lpstrFile:=ret;

   Open_File.lpstrFile[0]:=#0;

   Open_File.nMaxFile:=100000;

   Open_File.Flags := OFN_EXPLORER or OFN_FILEMUSTEXIST or OFN_ALLOWMULTISELECT;

   Open_File.lpstrDefExt:='.txt';

   Open_File.lpstrTitle:='My Program - Open File';

   Open_File.lpstrFilter:='All Files (*.*)'+#0+'*.*'+#0;

   File_Stringlist:=TStringlist.Create;

   If paramstr(1)<>'' then

      Begin

         Target_File:=paramstr(1);

         Process_File(Target_File);

      End

   else

      Target_File:='';

   Repeat

      If Target_File<>'' then

         Begin

            // The following line seems to cause my program to crash.

            // It does seem to work as I expect.  It puts me in the directory

            // of the file and shows the file name, but for some reason if I select

            // more than one file than I get

            // An unhandled exception occurred at $0040B428:

            // EAccessViolation:

            // $0040B428

            // $0040A03D

            // $00414447

            // $0040AE1E

            // $0040A03D

            // $00414447

            // $0040AE1E

            // $0040A03D

            // $00414447

            // $0040AE1E

            // $0040A03D

            // $00414447

            // $0040AE1E

            // $0040A03D

            // $00414447

            // $0040AE1E

            // $0040A03D

            // in a repeating loop if I use the command with two #0 at the end of

            // Open_File.lpstrFile:=Pchar(Target_File+#0+#0);

           

            // Or I get:

            // EAccessViolation: An unhandled exception occurred at $0040BB56:

            // with an exit code of 253

            // or

            // An unhandled exception occurred at $0040BDD2:

            // EAccessViolation: Access violation

            // $0040BDD2

            // with an exit with a code 217

            // if I use one #0 at the end of

            // Open_File.lpstrFile:=Pchar(Target_File+#0);

           

            // these errors seem to show up more if I select multiple files or

            // change directories. 

            Open_File.lpstrFile:=Pchar(Target_File+#0);

           

            

            // If I leaved the above commented out, then I should be able to use the

            // command below to just put me in the directory specified, but with no default file

            // This does not work the way I expect it to work at all.

            // It does not put me into the directory of the file used as a parameter, it

            // Then for other files it puts me one level before the one I was just in

            // I want to be back where I was.  If I give it a parameter, I want to

            // be in the directory of the file the parameter specifies, and then

            // I want to be in the directory of the previous file.

            // This just is not working the way I expect but does not cause any crash.

            Open_File.lpstrInitialDir:=Pchar(ExtractFilePath(Target_File)+#0+#0);

         End;

      Get_Files_Into_Stringlist(File_Stringlist);

      Display_File_StringList(File_Stringlist);

      If (File_Stringlist.Count=1) and FileExists(File_Stringlist[0]) Then

         Begin

            Target_File:=File_Stringlist[0];

            Process_File(Target_File);

         End

      Else

      If (File_Stringlist.Count>1) Then

         Begin

            Filenum:=0;

            Repeat

               Inc(Filenum);

               If (Filenum<File_Stringlist.Count) Then

                  Begin

                     Target_File:=File_Stringlist[0];

                     If Target_File[Length(Target_File)]<>'\' Then

                        Target_File:=Target_File+'\';

                     Target_File:=Target_File+File_Stringlist[Filenum];

                     Process_File(Target_File);

                  End;

            Until Filenum>=File_Stringlist.Count;

         End;

   Until File_Stringlist.count=0;

   File_Stringlist.Free;

end.

{=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=}

 

 


_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: Getting multiple files from GetOpenFileNameA

Santiago A.
In reply to this post by Zaaphod
El 23/05/19 a las 13:52, James Richters escribió:

I have put together a program that demonstrates the issue I am having.  I have re-structured it a bit to try to make it more clear where the problem is.

While putting this together, I was able to get it to run fine with no problems if I did not try to put GetOpenFileNameA back to the directory of the last file I processed. Including a file sent in as a parameter.   If I set Open_File.lpstrFile:=Pchar(Target_File+#0+#0); where Target_File is the complete path and file name of the last file I processed,  If I select only one file, then the next time around it DOES work.. and will put me in the directory of Target_File and will show the filename of Target_File as a default, but if I select more than one file, the next time around, it crashes.. I have detailed the crash information in the sameple program comments.

Another way I wish to run this is to leave Open_File.lpstrFile alone and use Open_File.lpstrInitialDir to put me in the directory of the last processed file, but not specify a default filename.  I can’t get this to work correctly at all, but if I use Open_File.lpstrInitialDir without Open_File.lpstrFile then it does not crash,  I am just not put in the directory I expect to be in. 

 

Any Advice or suggestions on any of this, or on how I could improve the structure or methods of this program are greatly appreciated.


At the beginning you set
Open_File.lpstrFile:=ret;

That is right Open_File.lpstrFile points to "ret", and "ret" is an array of 100000, a good buffer.


The problem is here:
Open_File.lpstrFile:=Pchar(Target_File+#0+#0);
That is wrong. Now Open_File.lpstrFile doesn't point to "ret" anymore, now it points to a string with length(Target_File)+2. But Open_File.nMaxFile:=100000, so the GetOpenFileNameA thinks there is plenty of room, so rises no error and overwrites whatever is after Target_File+#0+#0.

instead of
Open_File.lpstrFile:=Pchar(Target_File+#0+#0);
write
ret:=Pchar(Target_File+#0)
You should initialize to "ret" in each loop, in fact, it should be initialized inside the procedure. and Open_File.lpstrFilter:='All Files (*.*)'+#0+'*.*'+#0; needs an extra #0;


In addition, just for style, instead of

Open_File.nMaxFile:=100000
write
Open_File.nMaxFile:=sizeOf(ret);

And why are all those variables global if they are only used inside the procedure?

And instead of this

            Filenum:=0;

            Repeat

               Inc(Filenum);

               If (Filenum<File_Stringlist.Count) Then

                  Begin

                     Target_File:=File_Stringlist[0];

                     If Target_File[Length(Target_File)]<>'\' Then

                        Target_<a class="moz-txt-link-freetext" href="File:=Target_File+'\">File:=Target_File+'\';

                     Target_File:=Target_File+File_Stringlist[Filenum];

                     Process_File(Target_File);

                  End;

            Until Filenum>=File_Stringlist.Count;


Replace with

                              Target_File:=IncludeTrailingPathDelimiter(File_Stringlist[0]);

            for file_num:=1 to File_Stringlist.count-1 do

               Process_File(Target_File+File_Stringlist[Filenum]);


FOR is you friend


-- 
Saludos

Santiago A.

_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: Getting multiple files from GetOpenFileNameA

Zaaphod

Thank you very much for explaining all this!!   I really don’t know what I would do without the helpful people here!

 

I didn’t know there was something like IncludeTrailingPathDelimiter, wow that sure is useful!   I have a LOT of places I need to make sure I stick in the trailing \ and this function will really help clean up a lot of that mess!

 

I did not realize Open_File.lpstrFile was working like a pointer to Ret…  knowing that makes things make more sense!  I thought setting Open_File.lpstrFile:=Ret was just a way to initialize it, not that it was actually a pointer to Ret.

Should I just never use Open_File.lpstrFile except to set it to Ret (which I will probably rename to make it more clear that THAT is the real location of all my file name data)

So in other words do

 

         Repeat

            String_List.add(StrPas(Ret[Position_of_Filename]));

            inc(Position_of_Filename,length(String_List[String_List.Count-1])+1);

         Until Ret[Position_of_Filename]=#0;

 

The reason I made those variables global is because I set the initial ones in the main program loop… no real reason for doing that other than I thought it might help my crash issues if I wasn’t constantly creating and destroying those variables.  It does seem like a good idea to initialize every time so I’ll move all that into the function.

 

I’ve incorporated the recommended changes and still have a few problems.

 

Here is my updated sample program.  I renamed Ret to Open_File_Buffer and I am only using that variable after Open_File.lpstrFile:=Open_File_Buffer;  my problems still show up only if I try to set a default file with Open_File_Buffer:=Pchar(Target_File+#0+#0);   I’m not sure if I am doing this right.  It seems to put it in there but then if I select more than one file, it returns a False, and I also get crashes occasionally as well.  Open_File.lpstrInitialDir seems to work better but it only works if I do not try to set a default file name.  sometimes want a default file name, sometimes I do not, but I always want to set the initial directory, so I would like to learn the proper way to achieve both of these.

 

Thank you again for the help and the great suggestions!   It’s very much appreciated.

 

James

 

 

{$mode objfpc}{$H+}

//   https://docs.microsoft.com/en-us/windows/desktop/api/commdlg/nf-commdlg-getopenfilenamea

//   https://docs.microsoft.com/en-us/windows/desktop/api/commdlg/ns-commdlg-tagofna

Uses

  sysutils,Windows,Commdlg,Classes,CRT;

Var

File_Num           : Word;

Target_File        : AnsiString;

File_Stringlist    : tstringList;

{=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=}

Procedure Display_File_StringList(Var Display_String_List:tStringList);

Var

  SL_Loop : Word;

Begin

   If Display_String_List.Count=0 then

      Begin

         Textcolor(12);

         Writeln('0 Files Selected')

      End

   Else

   If Display_String_List.Count=1 then

      Begin

         TextColor(10);

         Writeln(Display_String_List[0]);

         Textcolor(14);

         Writeln('1 Files Selected');

      End

   Else

      Begin

         TextColor(13);

         Writeln('Path for all files: ',Display_String_List[0]);

         TextColor(10);

         For SL_Loop:= 1 to Display_String_List.Count-1 Do

            Writeln('File #',SL_Loop,': ',Display_String_List[SL_Loop]);

         Textcolor(14);

         Writeln(Display_String_List.Count-1,' Files Selected');

      End;

End;

{=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=}

Function Get_Files_Into_Stringlist(Var String_List:tStringList):Boolean;

Var

   Open_File_Result      : Boolean;

   Position_of_Filename  : Word;

   Open_File             : TOpenFileNameA;

   Open_File_Buffer      : array[0..100000] of char;

Begin

   String_List.Clear;

   fillchar(Open_File, sizeof(Open_File), 0);

   fillchar(Open_File_Buffer, sizeof(Open_File_Buffer), 0);

   Open_File.lStructSize:=sizeof(Open_File);

   Open_File.lpstrFile:=Open_File_Buffer;

   Open_File.nMaxFile:=SizeOf(Open_File_Buffer);

   Open_File.hwndOwner:=0;

   Open_File.Flags := OFN_EXPLORER or OFN_FILEMUSTEXIST or OFN_ALLOWMULTISELECT;

   Open_File.lpstrDefExt:='.txt';

   Open_File.lpstrTitle:='My Program - Open File';

   Open_File.lpstrFilter:='All Files (*.*)'+#0+'*.*'+#0;

   If Target_File<>'' then

       Begin

          // The line below makes GetOpenFileNameA return with False if I select more than one file.

          // It also causes the following occasionally:

          // An unhandled exception occurred at $00401B5A:

          // EAccessViolation: Access violation

          // $00401B5A  GET_FILES_INTO_STRINGLIST,  line 66 of i:/programming/gcode/test/getfilenamea to stringlist.pas

          // $00401E60  main,  line 99 of i:/programming/gcode/test/getfilenamea to stringlist.pas

          Open_File_Buffer:=Pchar(Target_File+#0+#0);

         //If the line below is un commmented, it selects multiple files from the correct directory, but only if the line above is commented out

          //Open_File.lpstrInitialDir:=Pchar(ExtractFilePath(Paramstr(1))+#0+#0);

       End;

   Open_File_Result:=GetOpenFileNameA(@Open_File);

   If Open_File_Result then

      Begin

         Position_of_Filename:=0;

         Repeat

            String_List.add(StrPas(@Open_File_Buffer[Position_of_Filename]));

            inc(Position_of_Filename,length(String_List[String_List.Count-1])+1);

         Until Open_File_Buffer[Position_of_Filename]=#0;

      End;

   Writeln(Open_File_Result);

   Get_Files_Into_Stringlist:=Open_File_Result;

End;

{=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=}

Procedure Process_File(Some_File: AnsiString);

Begin

   TextColor(11);

   Writeln('Processing File: ',Some_File);

End;

{=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=}

Begin {Main Program}

   File_Stringlist:=TStringlist.Create;

   If paramstr(1)<>'' then

      Begin

         Target_File:=paramstr(1);

         Process_File(Target_File);

      End

   else

      Target_File:='';

   Repeat

      Get_Files_Into_Stringlist(File_Stringlist);

      Display_File_StringList(File_Stringlist);

      If (File_Stringlist.Count=1) and FileExists(File_Stringlist[0]) Then

         Begin

            Target_File:=File_Stringlist[0];

            Process_File(Target_File);

         End

      Else

      If (File_Stringlist.Count>1) Then

         Begin

            Target_File:=IncludeTrailingPathDelimiter(File_Stringlist[0]);

            for file_num:=1 to File_Stringlist.count-1 do

               Process_File(Target_File+File_Stringlist[File_Num]);

         End;

   Until File_Stringlist.count=0;

   File_Stringlist.Free;

end.

{=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=+=-=}


_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal

Getfilenamea to Stringlist.pas (5K) Download Attachment