Re: [fpc-pascal] GetSaveFileNameA limited to 100 characters in default name

2021-06-21 Thread James Richters via fpc-pascal
>It's best to think of these in two parts. The Windows API part and then the 
>interfacing with Pascal part.
>SaveAsFileName.lpstrFile = long pointer to a (C) string filename buffer
>This buffer isn't created for you, you provide it and tell Windows it's size.

Thank you for the explanation, that explains why it crashed without the buffer 
but was fine with it.  For some reason I thought SaveAsFileName.lpstrFile was a 
Pchar Variable. 

James  

___
fpc-pascal maillist  -  fpc-pascal@lists.freepascal.org
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal


Re: [fpc-pascal] GetSaveFileNameA limited to 100 characters in default name

2021-06-21 Thread Alexander Grotewohl via fpc-pascal
It's best to think of these in two parts. The Windows API part and then the 
interfacing with Pascal part.

SaveAsFileName.lpstrFile = long pointer to a (C) string filename buffer

This buffer isn't created for you, you provide it and tell Windows it's size.

If you were to just do

StrPLCopy( SaveAsFileName.lpstrFile, DefaulSaveAsFileName, Max_Path+1);

there is no buffer there to receive DefaultSaveAsFileName. (or more correctly 
the lpstrFile pointer will point to random memory).

So, you first create the buffer, StrPLCopy the default string into it, and then 
pass it to the Windows API.

On return, it uses that same buffer (Windows doesn't have to create the buffer 
because you did) and knows the maximum it can place into the buffer (because 
you provided that information).

Afterwards you can take that buffer (a C-string) and convert it to something 
Pascal-like again.

This is important because almost everything you do with the Windows API will be 
some variant of this procedure and you need to be able to repeat this every 
time you use it without bugs 

--
Alexander Grotewohl
https://dcclost.com

From: fpc-pascal  on behalf of James 
Richters via fpc-pascal 
Sent: Monday, June 21, 2021 1:56 PM
To: 'FPC-Pascal users discussions' 
Cc: James Richters ; 'Jean SUZINEAU' 

Subject: Re: [fpc-pascal] GetSaveFileNameA limited to 100 characters in default 
name

>I would prefer to use
> StrPLCopy( SaveAsFileNameBuffer, DefaulSaveAsFileName,
SizeOf(SaveAsFileNameBuffer));
>instead of
>  SaveAsFileNameBuffer:=Pchar(DefaulSaveAsFileName);

I'm curious what the difference is between StrPLCopy() and PChar()

I wonder if PChar() was my problem.. maybe I don't need the buffer, maybe I
just needed:
StrPLCopy( SaveAsFileName.lpstrFile, DefaulSaveAsFileName, Max_Path+1);
?

James

___
fpc-pascal maillist  -  fpc-pascal@lists.freepascal.org
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
___
fpc-pascal maillist  -  fpc-pascal@lists.freepascal.org
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal


Re: [fpc-pascal] GetSaveFileNameA limited to 100 characters in default name

2021-06-21 Thread James Richters via fpc-pascal
>I would prefer to use 
> StrPLCopy( SaveAsFileNameBuffer, DefaulSaveAsFileName,
SizeOf(SaveAsFileNameBuffer));
>instead of 
>  SaveAsFileNameBuffer:=Pchar(DefaulSaveAsFileName);

I'm curious what the difference is between StrPLCopy() and PChar()

I wonder if PChar() was my problem.. maybe I don't need the buffer, maybe I
just needed:
StrPLCopy( SaveAsFileName.lpstrFile, DefaulSaveAsFileName, Max_Path+1);
?

James

___
fpc-pascal maillist  -  fpc-pascal@lists.freepascal.org
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal


Re: [fpc-pascal] GetSaveFileNameA limited to 100 characters in default name

2021-06-21 Thread James Richters via fpc-pascal
I have it working better now.  
I was having a crash with Code 216 
Appearantly 
   SaveAsFileName.lpstrFile:= Pchar(DefaulSaveAsFileName);
Just doesn't work the way I want it to.  If I try to do the conversion to
Pchar that way, I get an error 216 on:
  SaveAsResult:=GetSaveFileNameA(@SaveAsFileName);
 
I ended up making a buffer
SaveAsFileNameBuffer: array[0..Max_Path+1] of char;
 
Then putting my default file name in the buffer with:
SaveAsFileNameBuffer:=Pchar(DefaulSaveAsFileName);
 
Then assigning the buffer with:
SaveAsFileName.lpstrFile:=SaveAsFileNameBuffer;
 
So even though it looks like that would be the same thing as:
SaveAsFileName.lpstrFile:= Pchar(DefaulSaveAsFileName);It is not.. and
even though I had  SaveAsFileName.nMaxFile:=Max_Path+1;
SaveAsFileName.lpstrFile:= Pchar(DefaulSaveAsFileName);   still fails with a
216
 
Here is my complete test program, I'm not positive it's completely correct,
but it seems to work better:
 
Program TestGetSaveFileNameA;
Uses windows, commdlg;
 
Var
SaveAsFileName   : TOpenFileNameA;
SaveAsResult : Boolean;
DefaulSaveAsFileName,OutpuSaveAsFileName : Ansistring;
SaveAsFileNameBuffer: array[0..Max_Path+1] of char;
MyFile : Text;
 
Begin
   DefaulSaveAsFileName := 'X:\Something with a really really really long
long long long file name to see if there is still a bug with really long
filenames.tap';
   fillchar(SaveAsFileName, sizeof(SaveAsFileName), 0);
   SaveAsFileName.lStructSize:=sizeof(SaveAsFileName);
   SaveAsFileName.hwndOwner:=0;
   SaveAsFileName.nMaxFile:=Max_Path+1;
//   SaveAsFileName.lpstrFile:=Pchar(DefaulSaveAsFileName);// This
causes an Error 216
   SaveAsFileNameBuffer:=Pchar(DefaulSaveAsFileName);
   SaveAsFileName.lpstrFile:=SaveAsFileNameBuffer;
   SaveAsFileName.lpstrFilter:='TAP Files (*.tap)'+#0+'*.tap'+#0;
   SaveAsFileName.Flags := OFN_EXPLORER;
   SaveAsFileName.lpstrDefExt:='tap';
   SaveAsFileName.lpstrTitle:='Save File As:';
   Writeln(SaveAsFileName.lpstrFile,' ',SaveAsFileName.nMaxFile);
   SaveAsResult:=GetSaveFileNameA(@SaveAsFileName);
   Writeln(SaveAsResult,'  File Name Selected: ',SaveAsFileName.lpstrFile);
   If SaveAsResult then
  Begin
 OutpuSaveAsFileName:=strpas(SaveAsFileName.lpstrFile);
 Writeln('File Name AnsiString: '+OutpuSaveAsFileName);
 Assign(MyFile,OutpuSaveAsFileName);
 ReWrite(MyFile);
 Writeln(MyFile,'Test');
 Writeln(MyFile,OutpuSaveAsFileName);
 Close(MyFile);
  End;
End.
 
James
___
fpc-pascal maillist  -  fpc-pascal@lists.freepascal.org
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal


Re: [fpc-pascal] GetSaveFileNameA limited to 100 characters in default name

2021-06-21 Thread James Richters via fpc-pascal
>It's curious, I'm not completely sure we are reasoning about the same
function and record.
It seems I should not be using TFilename as the variable name.
I'm usinga variable called TFileName with GetSaveFileNameA() 
Here is the relevant code.. after I fixed it to use Max_Path
 
Uses CRT,CRT.Helper,Classes,Sysutils,windows,commdlg,Math,Process;
 
Var
   TFilename   : TOpenFileNameA;
   DefaultFileName   : AnsiString = '' ;
   OutputFileName   : AnsiString = '' ;
 
fillchar(TFileName, sizeof(TFileName), 0);
TFileName.lStructSize:=sizeof(TFileName);
TFileName.hwndOwner:=0;
TFileName.nMaxFile:=Max_Path+1;
TFileName.lpstrFile:=Pchar('');
TFileName.Flags := OFN_EXPLORER or OFN_FILEMUSTEXIST or OFN_HIDEREADONLY;
TFileName.lpstrDefExt:='';
TFileName.lpstrTitle:='Save File As:';
TFileName.lpstrFilter:='TAP Files (*.Tap)'+#0+'*.Tap'+#0+'All Files
(*.*)'+#0+'*.*'+#0;
TFileName.lpstrFile:=Pchar(DefaultFileName);
SaveAsResult:=GetSaveFileNameA(@TFilename);
.
.
OutputFileName:= strpas(TFileName.lpstrFile);
.
. 
Assign(TapFile,OutputFileName);
ReWrite(TapFile);
.
.
 
It seems TFileName is already defined and I am re-defining it.  TFileName
was not my idea.. that is not how I name my variables. It's something I got
from an example on how to use GetSaveFileNameA() that I copied and pasted
and then adjusted. that is also where TFileName.nMaxFile:=100; came from
that caused my original problem.
 
I don't have a really good understanding of the conventions of putting
various letters in front of Variables, like the T.. but I would never put
the T there myself.. variables I define never have the T.. so if I wasn't
copying an example, I would have done something like:
 
SaveAsFile : TOpenFileNameA;
 
James
___
fpc-pascal maillist  -  fpc-pascal@lists.freepascal.org
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal


Re: [fpc-pascal] GetSaveFileNameA limited to 100 characters in default name

2021-06-20 Thread Jean SUZINEAU via fpc-pascal


Le 21/06/2021 à 03:04, James Richters a écrit :

Var
    ...
DefaulSaveAsFileName: Ansistring;

SaveAsFileNameBuffer: array[0..Max_Path+1] of char;

   ...

Begin

DefaulSaveAsFileName := 'X:\Something with a really really really long 
long long long file name to see if there is still a bug with really 
long filenames.tap';


...
SaveAsFileNameBuffer:=Pchar(DefaulSaveAsFileName);
...

This sounds a bit odd to me but it seems to work.
I would prefer to use

  StrPLCopy( SaveAsFileNameBuffer, DefaulSaveAsFileName, 
SizeOf(SaveAsFileNameBuffer));


instead of
SaveAsFileNameBuffer:=Pchar(DefaulSaveAsFileName);


___
fpc-pascal maillist  -  fpc-pascal@lists.freepascal.org
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal


Re: [fpc-pascal] GetSaveFileNameA limited to 100 characters in default name

2021-06-19 Thread Jean SUZINEAU via fpc-pascal
I think you should have a look at this documentation on strings, 
particularly for PChar :

https://www.freepascal.org/docs-html/ref/refsu9.html

Le 20/06/2021 à 02:09, James Richters a écrit :

DefaultFileName: AnsiString = '' ;

So Length(DefaultFileName) = 0

TFileName.nMaxFile:=Max_Path+1;

This says that lpstrFile points to a buffer of size Max_Path+1.


TFileName.lpstrFile:=Pchar('');

But here you make it point to a buffer of size 1 (a constant with just a 
null char)


TFileName.Flags:= OFN_EXPLORER or OFN_FILEMUSTEXIST or OFN_HIDEREADONLY;


I think OFN_FILEMUSTEXIST forbid to create new file.


TFileName.lpstrFile:=Pchar(DefaultFileName);


New assignment of lpstrFile, make it point to DefaultFileName, which 
seems to be of length 0, so a buffer of size 1 (a constant with just a 
null char at the end).


I think you should at least add the begining of your code : SetLength( 
DefaultFileName, Max_Path);


It seems TFileName is already defined and I am re-defining 
it…TFileName was not my idea.. that is not how I name my variables…


The name is a bit misleading, but as soon as it's a variable of type 
TOpenFileNameA, it's fine.



___
fpc-pascal maillist  -  fpc-pascal@lists.freepascal.org
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal


Re: [fpc-pascal] GetSaveFileNameA limited to 100 characters in default name

2021-06-19 Thread Jean SUZINEAU via fpc-pascal
It's curious, I'm not completely sure we are reasoning about the same 
function and record.


You mention TFileName but for me in FPC 3.2.0:

-  TFileName is declared as "TFileName= type string;" in sysutilh.inc.

- OPENFILENAMEA is declared as record in CommDlg.pp line 94
  and TOPENFILENAMEA=OPENFILENAMEA;
  and POPENFILENAMEA=^OPENFILENAMEA;

-function GetSaveFileNameA is imported from Comdlg32.dll in CommDlg.pp 
line 595
  function GetSaveFileNameA(_para1:LPOPENFILENAME):WINBOOL; stdcall; 
external 'comdlg32' name 'GetSaveFileNameA';


Le 19/06/2021 à 02:51, James Richters via fpc-pascal a écrit :
This got me thinking… my default filename is just a recommended 
default… but TFileName.lpstrFileis also what returns the filename to 
use, and the user could use the save-as dialog to add a directory, and 
change the name of the file to something else..etc… so the file name 
could be significantly larger than the default…

Yes


So I think I’m best off setting TFileName.nMaxFile:= Max_Path;then 
TFileName.lpstrFile will always be able to hold anything the operating 
system can support.


The nMaxFile value include the terminal null character, so it should be 
Max_Path+1, and it must be the size of the buffer lpstrFile is pointing to.


You shouldn't use "TFileName.lpstrFile:=Pchar(DefaultFileName);" because 
in this case lpstrFile will point to a buffer of size 
Length(DefaultFileName)+1 .


And to get the value back from the function, given a variable s: string, 
you should do something like s:= StrPas( TFileName.lpstrFile);


From Microsoft documentation:

nMaxFile
The size, in characters, of the buffer pointed to by lpstrFile. The 
buffer must be large enough to store the path and file name string or 
strings, including the terminating NULL character. The GetOpenFileName 
 
and GetSaveFileName 
 
functions return FALSE if the buffer is too small to contain the file 
information. The buffer should be at least 256 characters long.



___
fpc-pascal maillist  -  fpc-pascal@lists.freepascal.org
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal


Re: [fpc-pascal] GetSaveFileNameA limited to 100 characters in default name

2021-06-18 Thread James Richters via fpc-pascal
>MAX_PATH itself seems to be an alias from system unit where it is defined
accordingly to the operating system (260 on windows, 4096 on Linux, 1024 on
BSD, Solaris and Darwin).
>It's unlikely, but this way you can end up with the corruption of the byte
right  after the memory block DefaultFileName is pointing to .
This got me thinking. my default filename is just a recommended default. but
TFileName.lpstrFile is also what returns the filename to use, and the user
could use the save-as dialog to add a directory, and change the name of the
file to something else..etc. so the file name could be significantly larger
than the default. 
So I think I'm best off setting TFileName.nMaxFile := Max_Path;  then
TFileName.lpstrFile will always be able to hold anything the operating
system can support. 
James
 
___
fpc-pascal maillist  -  fpc-pascal@lists.freepascal.org
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal


Re: [fpc-pascal] GetSaveFileNameA limited to 100 characters in default name

2021-06-18 Thread Jean SUZINEAU via fpc-pascal

I haven't seen your reply.
Le 18/06/2021 à 23:50, James Richters via fpc-pascal a écrit :

So now I have:

TFileName.nMaxFile:= Length(DefaultFileName)+1;

TFileName.lpstrFile:=Pchar(DefaultFileName);

I need the +1 for the #0 at the end of the Pchar, and now it works 
fine, and I can have strings as long as they need to be.


I think that this way you tell GetSaveFileNameA that it can write 
Length(DefaultFileName)+1 chars in Pchar(DefaultFileName),
but you have only allocated Length(DefaultFileName) chars to 
DefaultFileName .


It's unlikely, but this way you can end up with the corruption of the 
byte right  after the memory block DefaultFileName is pointing to ...



___
fpc-pascal maillist  -  fpc-pascal@lists.freepascal.org
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal


Re: [fpc-pascal] GetSaveFileNameA limited to 100 characters in default name

2021-06-18 Thread Jean SUZINEAU via fpc-pascal
I'm not familiar with GetSaveFileNameA, but usually for the size of a 
FileName  buffer I use the constant MAX_PATH which is defined in unit 
SysUtils.


MAX_PATH itself seems to be an alias from system unit where it is 
defined accordingly to the operating system (260 on windows, 4096 on 
Linux, 1024 on BSD, Solaris and Darwin).


Did you have a look at Microsoft's documentation for GetSaveFileNameA 
and the OPENFILENAMEA structure it takes as parameter ?

https://docs.microsoft.com/en-us/windows/win32/api/commdlg/nf-commdlg-getsavefilenamea

https://docs.microsoft.com/en-us/windows/win32/api/commdlg/ns-commdlg-openfilenamea

Particularly, you need to put in |nMaxFile |the size of the buffer 
pointed to by lpstrFile.


The folowing code works with a 120 characters long filename :

program test_GetSaveFileName;
uses
    SysUtils, CommDlg;
const DefaultFilename= 'Test';
var
   Buffer: array[0..MAX_PATH] of Char; //size MAX_PATH + 1 for 
terminating null char

   ofn: TOPENFILENAMEA;
begin
 StrPLCopy( Buffer, DefaultFilename, MAX_PATH);
 ofn.lStructSize:= sizeof(ofn);
 ofn.hInstance:= 0;
 ofn.lpstrFilter:= nil;
 ofn.lpstrCustomFilter:= nil;
 ofn.nMaxCustFilter:= 0;
 ofn.nFilterIndex:= 0;
 ofn.lpstrFile:= Buffer;
 ofn.nMaxFile:= Sizeof( Buffer);
 ofn.lpstrFileTitle:= nil;
 ofn.nMaxFileTitle:= 0;
 ofn.lpstrInitialDir:= nil;
 ofn.lpstrTitle:= 'test GetSaveFileNameA';
 ofn.Flags:= 0;
 ofn.nFileOffset:= 0;
 ofn.nFileExtension:= 0;
 ofn.lpstrDefExt:= nil;
 ofn.lCustData:= 0;
 ofn.lpfnHook:= nil;
 ofn.lpTemplateName:= nil;
 ofn.pvReserved:= nil;
 ofn.dwReserved:= 0;
 ofn.FlagsEx:= 0;
 if GetSaveFileNameA( @ofn)
 then
 WriteLn( ofn.lpstrFile);
end.

___
fpc-pascal maillist  -  fpc-pascal@lists.freepascal.org
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal


Re: [fpc-pascal] GetSaveFileNameA limited to 100 characters in default name

2021-06-18 Thread James Richters via fpc-pascal
I'm converting my AnsiString to a Pchar with 
TFileName.lpstrFile:=Pchar(DefaultFileName);
 
But I didn't understand the meaning of 
TFileName.nMaxFile:=100;  I thought it was the maximum number of files to
display or something.. not the maximum number of characters in the file
name. which it appears to be.
 
So now I have:
TFileName.nMaxFile:= Length(DefaultFileName)+1; 
TFileName.lpstrFile:=Pchar(DefaultFileName);
 
I need the +1 for the #0 at the end of the Pchar,  and now it works fine,
and I can have strings as long as they need to be.
 
Thank you for the help!
 
James
___
fpc-pascal maillist  -  fpc-pascal@lists.freepascal.org
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal


Re: [fpc-pascal] GetSaveFileNameA limited to 100 characters in default name

2021-06-18 Thread Alexander Grotewohl via fpc-pascal
The Windows API doesn't understand what an 'AnsiString' is and cannot resize it 
dynamically like FreePascal would do as it is used.

You need to use something like

buf: array[0..512] of char;

TFileName.nMaxFile := sizeof(buf);

But then you should also handle the possibility that the dir is greater than 
512 and allocate a bigger buffer as needed.
So maybe dynamically allocating the space would be better.

--
Alexander Grotewohl
https://dcclost.com

From: fpc-pascal  on behalf of James 
Richters via fpc-pascal 
Sent: Friday, June 18, 2021 1:56 PM
To: 'FPC-Pascal users discussions' 
Cc: James Richters 
Subject: [fpc-pascal] GetSaveFileNameA limited to 100 characters in default name


I’m using GetSaveFileNameA() in a windows console program to obtain a save-as 
directory and file name, I am passing  sending it a default file name with:



TFileName.lpstrFile:=Pchar(DefaultFileName);



DefaultFileName is an AnsiString that contains a full path and filename.



This all works fine as long as DefaultFileName is 100 characters or less,  if 
it’s 101 or more, then GetSaveFileNameA() never opens a dialog box and just 
returns False;



Does anyone know where the 100 character limit is coming from?



TFileName.lpstrFile is a PChar, and DefaultFileName is an AnsiString, Neither 
of which have a length limit that I know of…

I am doing a Writeln if Both DefaultFileName and TFileName.lpstrFile and they 
both match, nothing is being truncated.



James
___
fpc-pascal maillist  -  fpc-pascal@lists.freepascal.org
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal


[fpc-pascal] GetSaveFileNameA limited to 100 characters in default name

2021-06-18 Thread James Richters via fpc-pascal
I'm using GetSaveFileNameA() in a windows console program to obtain a
save-as directory and file name, I am passing  sending it a default file
name with:
 
TFileName.lpstrFile:=Pchar(DefaultFileName);
 
DefaultFileName is an AnsiString that contains a full path and filename.
 
This all works fine as long as DefaultFileName is 100 characters or less,
if it's 101 or more, then GetSaveFileNameA() never opens a dialog box and
just returns False;
 
Does anyone know where the 100 character limit is coming from?  
 
TFileName.lpstrFile is a PChar, and DefaultFileName is an AnsiString,
Neither of which have a length limit that I know of.
I am doing a Writeln if Both DefaultFileName and TFileName.lpstrFile and
they both match, nothing is being truncated.  
 
James
___
fpc-pascal maillist  -  fpc-pascal@lists.freepascal.org
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal