Warum wird Datei nicht erzeugt?

Für allgemeine Fragen zur Programmierung, welche nicht! direkt mit Lazarus zu tun haben.
Antworten
thosch
Beiträge: 219
Registriert: Mo 10. Jul 2017, 20:32

Warum wird Datei nicht erzeugt?

Beitrag von thosch »

Hallo,

ich habe folgendes Programm:

Code: Alles auswählen

unit main;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls, ShellCtrls,
  FileCtrl, EditBtn, Windows;


const
  DirSeparator = {$ifdef linux}'/'{$else}'\'{$endif};


type

  { TRegistryTest }

  TRegistryTest = class
  private
    FOutput: TStringList;
  public
    constructor Create;
    destructor Destroy; override;
    procedure CreateKeysAndOutputTo(aList: TStringList);
    property Output: TStringList read FOutput write FOutput;
  end;

  { TForm1 }

  TForm1 = class(TForm)
    btnCopy: TButton;
    edSrcDirectory: TDirectoryEdit;
    edDstDirectory: TDirectoryEdit;
    FileListBox1: TFileListBox;
    FileListBox2: TFileListBox;
    edSrcFileName: TFileNameEdit;
    FileNameEdit2: TFileNameEdit;
    Output: TMemo;
    procedure btnCopyClick(Sender: TObject);
    procedure FormClose(Sender: TObject; var CloseAction: TCloseAction);
    procedure FormCreate(Sender: TObject);
  private
    FTest: TRegistryTest;
  public

  end;

var
  Form1: TForm1;

implementation

{$R *.lfm}

{$I strcast.inc}


function GetCurDir: AnsiString;
var
  CurDir: AnsiString;
begin
  CurDir := GetCurrentDir;
  if CurDir[Length(CurDir)] <> DirSeparator then CurDir := CurDir + DirSeparator;
  Result := CurDir;
end;


{ TRegistryTest }

constructor TRegistryTest.Create;
begin
  inherited Create;
  FOutput := TStringList.Create;
end;

destructor TRegistryTest.Destroy;
begin
  FOutput.Free;
  inherited Destroy;
end;

procedure TRegistryTest.CreateKeysAndOutputTo(aList: TStringList);
begin
  FOutput.Assign(aList);
end;

{ TForm1 }

procedure TForm1.FormClose(Sender: TObject; var CloseAction: TCloseAction);
begin
  FTest.Free;
end;

procedure TForm1.btnCopyClick(Sender: TObject);
var
  DstDir,SrcFile,Filename: AnsiString;
  lpDstDir,lpSrcFile,lpFileName: LPCSTR;
  lpwDstDir,lpwSrcFile,lpwFilename: LPCWSTR;
begin
  
end;

procedure TForm1.FormCreate(Sender: TObject);
var
  CurDir: AnsiString;
  DstDir,SrcFile,Filename: AnsiString;
  lpDstDir,lpSrcFile,lpFileName: LPCSTR;
  lpwDstDir,lpwSrcFile,lpwFilename: LPCWSTR;
begin
  //FTest:= TRegistryTest.Create;

  //FTest.CreateKeysAndOutputTo(TStringList(Output.Lines));

  CurDir := GetCurrentDir;
  if CurDir[Length(CurDir)] <> DirSeparator then CurDir := CurDir + DirSeparator;
  edSrcDirectory.Directory := CurDir;

  FileName := GetCurDir+'MeinTestFile.txt';
  //ShowMessage(FileName);
  AnsiToLpc(FileName,lpFileName);
  CreateFileA(lpFileName,GENERIC_READ or GENERIC_WRITE,0,nil,CREATE_NEW,FILE_ATTRIBUTE_NORMAL,0);

end;

end.
Damit will ich die Datei 'MeinTestFile.txt' neu erzeugen, was aber nicht passiert. Warum?

Benutzeravatar
kralle
Lazarusforum e. V.
Beiträge: 714
Registriert: Mi 17. Mär 2010, 14:50
OS, Lazarus, FPC: Linux Mint 20 , FPC 3.3.1 , Lazarus 2.1.0 -Win10 & XE7Pro
CPU-Target: 64Bit
Wohnort: Bremerhaven
Kontaktdaten:

Re: Warum wird Datei nicht erzeugt?

Beitrag von kralle »

Moin,

wo definierst Du diese Funktion/Procedure

Code: Alles auswählen

 CreateFileA
?

Bekommst Du irgendeine Fehlermeldung, weil

Code: Alles auswählen

 CreateFileA
nicht gefunden wird?

Gruß HEiko
Linux Mint 20.1, FPC-Version: 3.3.1 , Lazarus 2.1.0
+ Delphi XE7SP1

Benutzeravatar
h-elsner
Beiträge: 99
Registriert: Di 24. Jul 2012, 15:42
OS, Lazarus, FPC: LINUX Mint18.3, Win10, Lazarus 2.0.8, FPC3.0.4
CPU-Target: 64Bit
Wohnort: Illertissen
Kontaktdaten:

Re: Warum wird Datei nicht erzeugt?

Beitrag von h-elsner »

Ich muss gestehen, dass ich das Programm überhaupt nicht verstehe. Das ist mir leider zu hoch.
Aber wenn ich eine StringList speichern will, dann nehme ich:

Code: Alles auswählen

FOutput.SaveToFile(irgendein_filename);
Die Datei wird mit Inhalt angelegt und fertig.

Was sollen die ganzen AnsiString Sachen? Ich bin froh un d glücklich, dass Lazarus UTF-8 benutzt und ich mir keine Gedanken über Umlaute und Sonstiges in Pfaden und Dateinamen machen muss.

Benutze "PathDelim" anstatt deinen selbst-definierten "DirSeparator", dann musst du dir über '/' oder '\' keine Gedanken machen.

Code: Alles auswählen

if CurDir[Length(CurDir)] <> DirSeparator then CurDir := CurDir + DirSeparator;
Dies kann ersetzt werden mit

Code: Alles auswählen

CurDir:=IncludeTrailingPathDelimiter(CurDir);
Gruß HE

Benutzeravatar
h-elsner
Beiträge: 99
Registriert: Di 24. Jul 2012, 15:42
OS, Lazarus, FPC: LINUX Mint18.3, Win10, Lazarus 2.0.8, FPC3.0.4
CPU-Target: 64Bit
Wohnort: Illertissen
Kontaktdaten:

Re: Warum wird Datei nicht erzeugt?

Beitrag von h-elsner »

Dies habe ich gerade mal ausprobiert, um eine leere Datei zu erzeugen:

Code: Alles auswählen

procedure TForm1.btnCreateFileClick(Sender: TObject);
var fs: TFileStream;
    fn: string;
begin
  fn:=IncludeTrailingPathDelimiter(GetCurrentDir)+'MeinTestFile.txt';
  fs:=TFileStream.Create(fn, fmCreate);
  try
    ShowMessage(fn+' erzeugt');
  finally
    fs.Free;
  end;
end;

wp_xyz
Beiträge: 3518
Registriert: Fr 8. Apr 2011, 09:01

Re: Warum wird Datei nicht erzeugt?

Beitrag von wp_xyz »

Etwas kürzer ist das AppendPathDelim in der Unit LazFileUtils (welcher Masochist bei Borland hat sich diesen Funktionsnamen ausgedacht: "IncludeTrailingPathDelimiter"?:

Code: Alles auswählen

uses
  LazFileUtils;
  ...
  fn:=AppendPathDelim(GetCurrentDir)+'MeinTestFile.txt';
Und Lazarus baut die Delimiter inzwischen um, so dass man in der Regel auch unter Windows einen Forward-Slash verwenden darf:

Code: Alles auswählen

  fn:='c:/test/daten/MeinTestFile.txt';

Benutzeravatar
Winni
Beiträge: 552
Registriert: Mo 2. Mär 2009, 16:45
OS, Lazarus, FPC: Laz2.06, fpc 3.04
CPU-Target: 64Bit
Wohnort: Fast Dänemark

Re: Warum wird Datei nicht erzeugt?

Beitrag von Winni »

Hi!
AppendPathDelim, DrectorySeparator und Artverwandtes setzen umgebungs abhängig korrekt Slash bzw. Backslash.
Also ist es portabler code.

Und gegen Bezeichner-Terrorismus gibt es ja Pascal:

const: ITPD = IncludeTrailingPathDelimiter;

Winni

PS.: Teste gerade Browser ohne JavaScript. die

Code: Alles auswählen

 Tags fallem dem Test zum Opfer.

thosch
Beiträge: 219
Registriert: Mo 10. Jul 2017, 20:32

Re: Warum wird Datei nicht erzeugt?

Beitrag von thosch »

[Quote="kralle]

wo definierst Du diese Funktion/Procedure CreateFileA?
[/quote]

Ups, ist die nicht in der Unit Windows enthalten? Ja, ich habe diese Funktion selber noch mal geschrieben, um den Aufbau des Windows API und dessen interne Arbeitweise zu verstehen. Sollte legal sein! Was illegal ist, wäre einen Kernel Debugger auf das Windows API anzusetzen und die Originalfunktion damit zu suchen und dort nachzuschauen wie sie funktioniert. Aber selber darüber Gedanken machen ist doch legal oder? Was ist mit ReactOS? Das ist doch auch binärkompatibel zu Windows? Ist das illegal?

Daher kommt auch KEINE Fehlermeldung "CreateFileA nicht gefunden". Die sollte in der Windows Unit deklariert sein und die Windows Unit ist in der Uses Klausel aufgeführt!

Nein in meinem Testprogramm wird hier die originale Windows API Funktion "CreateFileA" aufgerufen. Der Fehler tritt in meiner selber fdefinierten Funktion auch auf. Dort erzeuge ich die Datei mit TFileStream.Create(Filename,fmCreate), aber sie wird nicht erzeugt. Dann habe ich das Programm geändert und auch mit Aufruf der echten Windows API Funktion wird die Datei nicht erzeugt. Also muss der Fehler woanders liegen. In meinem Lazarus Verzeichnis in dem ich meine Projekte abspeichere habe ich doch Schreibrechte???? UNter Eindows? WIe schaut das unter Linux aus. Kann ich dort auch in meinem Projektordner die von mir entwickelten Programme Dateien speichern lassen? Oder muss ich da besondere Rechte vergeben? Der Create Konstruktor kann ja noch einen dritten Parameter aufnehmen, der diese Rechte steuert! Muss ich da noch was machen und wenn ja, wie geht da in Windows und wie in Linux????

Ich will also die WinAPI Funktion nachbauen!

Aber auch mit der originalen Funktion erhalte ich die Datei nicht, also liegt es nicht am Stream innerhalb der Funktion sondern an meinen Parametern.

Und da ist nun meine Frage, was mache ich da falsch?

PascalDragon
Beiträge: 222
Registriert: Mi 3. Jun 2020, 07:18
OS, Lazarus, FPC: L 2.0.8, FPC Trunk, OS Win/Linux
CPU-Target: Aarch64 bis Z80 ;)
Wohnort: München

Re: Warum wird Datei nicht erzeugt?

Beitrag von PascalDragon »

kralle hat geschrieben:
Fr 18. Dez 2020, 16:58
wo definierst Du diese Funktion/Procedure

Code: Alles auswählen

 CreateFileA
?
thosch inkludiert die Windows Unit im Code und dort sind sowohl CreateFileA, CreateFileW als auch CreateFile (als Alias auf CreateFileA) deklariert.
thosch hat geschrieben:
Fr 18. Dez 2020, 15:42
Hallo,

ich habe folgendes Programm:

Code: Alles auswählen

procedure TForm1.FormCreate(Sender: TObject);
var
  CurDir: AnsiString;
  DstDir,SrcFile,Filename: AnsiString;
  lpDstDir,lpSrcFile,lpFileName: LPCSTR;
  lpwDstDir,lpwSrcFile,lpwFilename: LPCWSTR;
begin
  //FTest:= TRegistryTest.Create;

  //FTest.CreateKeysAndOutputTo(TStringList(Output.Lines));

  CurDir := GetCurrentDir;
  if CurDir[Length(CurDir)] <> DirSeparator then CurDir := CurDir + DirSeparator;
  edSrcDirectory.Directory := CurDir;

  FileName := GetCurDir+'MeinTestFile.txt';
  //ShowMessage(FileName);
  AnsiToLpc(FileName,lpFileName);
  CreateFileA(lpFileName,GENERIC_READ or GENERIC_WRITE,0,nil,CREATE_NEW,FILE_ATTRIBUTE_NORMAL,0);

end;
Damit will ich die Datei 'MeinTestFile.txt' neu erzeugen, was aber nicht passiert. Warum?
Wenn du dich schon direkt mit der Windows API rumschlägst, dann aber auch bitte richtig:

1. das AnsiToLpc ist unnötig, du kannst ganz einfach PChar(FileName) nutzen, dann musst du dich auch nicht damit herumschlagen den lpFileName wieder freizugeben (ich nehme an dein AnsiToLpc erzeugt nen neuen PChar und kopiert die Daten um?)
2. die CreateFileA Funktion hat als Rückgabewert ein Handle auf die erzeugte/geöffnete Datei oder INVALID_HANDLE_VALUE falls das gescheitert ist (du musst dieses Handle auch wieder schließen!); in letzterem Fall solltest du Windows fragen was du falsch gemacht hast.

So oder so auf jeden Fall die Dokumentation auf dem MSDN studieren (das ist hier wichtiger als durch den Windows Code zu debuggen oder zu schauen wie das in ReactOS implementiert ist - auch wenn ich dir aus eigener Erfahrung sagen kann, dass das sehr interessant ist ;) ).

Also sollte dein Aufruf letztlich so aussehen:

Code: Alles auswählen

var
  hdl: THandle;
begin
  hdl := CreateFileA(PChar(FileName), GENERIC_READ or GENERIC_WRITE, 0, Nil, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0);
  if hdl = INVALID_HANDLE_VALUE then
    ShowMessage(SysErrorMessage(GetLastOSError))
  else
    CloseHandle(hdl);
end;
Zusätzliche Anmerkung: du kannst dein GetCurDir auch durch IncludeTrailingPathDelimiter(GetCurrentDir) ersetzen.
thosch hat geschrieben:
Sa 19. Dez 2020, 10:06
Nein in meinem Testprogramm wird hier die originale Windows API Funktion "CreateFileA" aufgerufen. Der Fehler tritt in meiner selber fdefinierten Funktion auch auf. Dort erzeuge ich die Datei mit TFileStream.Create(Filename,fmCreate), aber sie wird nicht erzeugt. Dann habe ich das Programm geändert und auch mit Aufruf der echten Windows API Funktion wird die Datei nicht erzeugt. Also muss der Fehler woanders liegen. In meinem Lazarus Verzeichnis in dem ich meine Projekte abspeichere habe ich doch Schreibrechte???? UNter Eindows? WIe schaut das unter Linux aus. Kann ich dort auch in meinem Projektordner die von mir entwickelten Programme Dateien speichern lassen? Oder muss ich da besondere Rechte vergeben? Der Create Konstruktor kann ja noch einen dritten Parameter aufnehmen, der diese Rechte steuert! Muss ich da noch was machen und wenn ja, wie geht da in Windows und wie in Linux????
TFileStream.Create nutzt intern auch (letztlich) einfach nur CreateFile (unter Windows). Wenn TFileStream.Create keine Exception auslöst dann wurde die Datei auch erzeugt, es kann nur sein, dass dein Pfad eventuell nicht das ist was du erwartest. Und du musst natürlich den Stream mit Free freigeben.
thosch hat geschrieben:
Sa 19. Dez 2020, 10:06
Ich will also die WinAPI Funktion nachbauen!
Ich würde dir empfehlen bei TFileStream oder der File*-API aus SysUtils zu bleiben, da diese die ganzen Platformunterschiede bereits abstrahieren. Wenn diese Klasse bzw. diese Funktionen die Datei nicht erzeugen und/oder öffnen können dann generieren sie einen Fehler (TFileStream als Exception, die File*-API als Rückgabewert), dann musst du prüfen was dir als Fehler gemeldet wird. Geben sie keinen Fehler zurück, dann musst du prüfen, was du ihnen als Pfad mitgegeben hast.
FPC Compiler Entwickler

MmVisual
Beiträge: 1150
Registriert: Fr 10. Okt 2008, 23:54
OS, Lazarus, FPC: Winuxarm (L 2.0.10 FPC 3.2)
CPU-Target: 32/64Bit

Re: Warum wird Datei nicht erzeugt?

Beitrag von MmVisual »

Mache das mit den Textdateien bitte nicht komplizierter als es ist. Verwende dazu am Besten die TStringList, da ist alles dabei was einem das Herz begehrt um auch die Texte in der EXE ganz einfach verwalten/verwenden zu können.

Code: Alles auswählen

Var sl: TStringList;  // ist eine Liste mit Strings, also so wie eine Textdatei mit Zeilen

sl := TStringList.Create;

sl.Add('Mein Test Text'); // Text hinzu fügen
sl.Values['Parameter'] := 'Wert1'; // Parameter direkt in der StringListe verwalten

sl.SaveToFile('MeinTestFile.txt'); // Text in Datei speichern

sl.LoadFromFile('MeinTestFile.txt'); // Text wieder lesen

sl.Free;

Antworten