2

I'm want write name of my pc to a txt file using SysUtils.FileWrite api, in my last attempt is wrote with sucess, but the trouble is that visually is cutting some characters, but size of text inside file have exactly the same size as if string is complete visually.

Eg: My pc is called of "TESTE-PC" (Without double quotes). The string "TESTE-PC" (Without double quotes) have exactly 8 bits, but SysUtils.FileWrite writes only "TEST" and size of file after is 8 bits. Very strange! :(

Thank you for any suggestion.

uses
 Registry;

...

function GetCompName: string;
var
  Reg: TRegistry;
begin
  Reg := TRegistry.Create;
  try
    Reg.rootKey := HKEY_LOCAL_MACHINE;
    if Reg.OpenKey('SYSTEM\CurrentControlSet\Control\ComputerName\ActiveComputerName', false) then
    begin
      Result := Reg.ReadString('ComputerName');
      Reg.CloseKey;
    end;
  finally
    Reg.Free;
  end;
end;

procedure TForm1.FormCreate(Sender: TObject);
var
 hFile: THandle;
 Str: PWideChar;
begin

if not fileexists('test.txt') then
begin
  Str := PWideChar(GetCompName);
  hFile:=  CreateFile('test.txt', GENERIC_WRITE, 0, nil, OPEN_ALWAYS, FILE_FLAG_WRITE_THROUGH, 0);
  FileWrite(hFile, Str^, Length(Str));
  CloseHandle(hFile);
end;

end;
1
  • What encoding do you want to use? Commented Nov 1, 2016 at 7:30

3 Answers 3

5

First off, using the Registry to get the computer name is wrong. Use the GetComputerName() function instead:

uses
  Windows;

...

function GetCompName: string;
var
  CompName: array[0..MAX_COMPUTERNAME_LENGTH] of Char;
  Size: DWORD;
begin
  Size := Length(CompName);
  if GetComputerName(CompName, Size) then
    SetString(Result, CompName, Size-1)
  else
    Result := '';
end;

Second, your FileWrite() code fails because you are not handling character encodings correctly. FileWrite() operates on raw bytes only, but you are working with Unicode strings and not taking into account that SizeOf(WideChar) is 2, not 1 like your code assumes.

You should also be using the RTL's FileCreate() function with FileWrite(). If you use the Win32 CreateFile() function directly, you should be using the Win32 API WriteFile() directly as well.

And no matter how you choose to write the file, you should be using an absolute path to the file, never a relative path.

Try something more like this:

procedure TForm1.FormCreate(Sender: TObject);
var
  FileName: string
  hFile: THandle;
  Str: string;
begin
  FileName := 'C:\path to\test.txt';
  if not FileExists(FileName) then
  begin
    Str := GetCompName;
    hFile := FileCreate(FileName);
    if hFile <> INVALID_HANDLE_VALUE then
    begin
      FileWrite(hFile, PChar(Str)^, Length(Str) * SizeOf(Char));
      FileClose(hFile);
    end;
  end;

Note that the code above will create the file in UTF-16 encoding. If you wanted to use UTF-8 instead, it would look like this:

procedure TForm1.FormCreate(Sender: TObject);
var
  FileName: string;
  hFile: THandle;
  Str: UTF8String;
begin
  FileName := 'C:\path to\test.txt';
  if not FileExists(FileName) then
  begin
    Str := UTF8String(GetCompName);
    hFile := FileCreate(FileName);
    if hFile <> INVALID_HANDLE_VALUE then
    begin
      FileWrite(hFile, PAnsiChar(Str)^, Length(Str));
      FileClose(hFile);
    end;
  end;

Or any other encoding, for that matter:

procedure TForm1.FormCreate(Sender: TObject);
var
  FileName: string;
  hFile: THandle;
  Enc: TEncoding;
  Str: TBytes;
begin
  FileName := 'C:\path to\test.txt';
  if not FileExists(FileName) then
  begin
    Enc := TEncoding.GetEncoding('desired encoding');
    try
      Str := Enc.GetBytes(GetCompName);
    finally
      Enc.Free;
    end;
    hFile := FileCreate(FileName);
    if hFile <> INVALID_HANDLE_VALUE then
    begin
      FileWrite(hFile, PByte(Str)^, Length(Str));
      FileClose(hFile);
    end;
  end;

Whatever encoding you decide to use, a simpler solution would be to use the IOUtils.TFile.WriteAllText() method instead:

uses
  IOUtils;

procedure TForm1.FormCreate(Sender: TObject);
var
  FileName: string;
begin
  FileName := 'C:\path to\test.txt';
  if not FileExists(FileName) then
  begin
    TFile.WriteAllText(FileName, GetCompName, TEncoding.UTF8); // or TEncoding.Unicode, etc...
  end;
end;
Sign up to request clarification or add additional context in comments.

Comments

0

If you need to write wide chars, take their size into account:

FileWrite(hFile, Str^, Length(Str) * SizeOf(Char));

Comments

-1

Change the type of str to RawByteString instead of PWideChar

procedure TForm1.FormCreate(Sender: TObject);
var
   hFile:  THandle;
   sFileName: string;
   Str: RawByteString;
begin
     Str := PWideChar(GetCompName);
     sFileName := 'Test.txt';
    if fileExists(sFileName) then
      hFile := fileOpen(sFileName,fmOpenReadWrite)
    else
      hFile := fileCreate(sFileName);
     try
       FileWrite(hFile,
        PChar(Str)^, Length(Str));
     finally
       FileClose(hFile);
     end;
end;

1 Comment

This is not how to use RawByteString. What encoding are you trying to use here.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.