如何在Delphi 2010中声明StreamLn

时间:2015-09-28 23:39:45

标签: delphi

我最近开始在delphi中编程,但不幸的是我在尝试编译以下代码时收到错误。

undeclared indentifier 'StreamLn'

我搜索了PSock,有人说它已被Winsock取代,但我不知道我是否仍然可以使用StreamLn

这是代码

unit ResourceInfo;
  {this tools is suppose to read Dfm data inside a Delphi executing}
  {and  save as .dfm ,.rc and .dat}
interface

uses
  Classes, SysUtils, Windows;

type
  TResourceInfo = class;

  TDfmMode = ( dfmData, dfmResource, dfmASCII, dfmBinary);

  TDfm = class
  private
    FOwner: TResourceInfo;
    FName: string;
    FData: TStream;

    procedure SetName(const Value: string);
    procedure SetOwner(const Value: TResourceInfo);

  public
    constructor Create(AOwner: TResourceInfo);
    destructor Destroy; override;

    function SaveToFile(FileName: TFileName; Mode: TDfmMode): Boolean;

    property Data: TStream read FData;
    property Name: string read FName write SetName;
    property Owner: TResourceInfo read FOwner write FOwner;
  end; {TDfm}

  TResourceInfo = class(TComponent)
  private
    FActive: Boolean;
    FDfms: TList;
    FExeFileName: TFileName;
    FModule: THandle;
    FOnActivate: TNotifyEvent;
    FOnDeactivate: TNotifyEvent;

    procedure SetExeFileName(const Value: TFileName);
    procedure SetActive(const Value: Boolean);
    function  GetDfms(Index: Cardinal): TDfm;
    function  GetDfmCount: Cardinal;

  protected
    procedure Clear;

  public
    constructor Create(AOwner: TComponent); override;
    destructor  Destroy; override;

    function  AddDfm(const Name: string; AData: TMemoryStream): Integer;
    procedure DeleteDfm(const Name: string);
    property  DfmCount: Cardinal read GetDfmCount;
    property  Dfms[Index: Cardinal]: TDfm read GetDfms;
    procedure EnumDfmNames;
    property  Module: THandle read FModule;

  published
    property Active: Boolean read FActive write SetActive;
    property ExeFileName: TFileName read FExeFileName write SetExeFileName;

    property OnActivate: TNotifyEvent read FOnActivate write FOnActivate;
    property OnDeactivate: TNotifyEvent read FOnDeactivate write FOnDeactivate;
  end; {TResourceInfo}

procedure Register;

implementation

uses
 Winsock;

resourcestring
  rsErrorLoadingExeFile = 'An error ocurred loading file %s, it may not be an executable module';

procedure Register;
begin
  RegisterComponents('+HCU', [TResourceInfo]);
end; {Register}

{ TResourceInfo }

function TResourceInfo.AddDfm(const Name: string; AData: TMemoryStream): Integer;
var
  FDfm: TDfm;
begin
  FDfm := TDfm.Create(Self);
  FDfm.Name := Name;
  FDfm.Data.Size := AData.Size;
  FDfm.Data.Seek(0, 0);
  AData.Seek(0, 0);
  FDfm.Data.CopyFrom(AData, AData.Size);
  Result := FDfms.Add(FDfm);
end; {TResourceInfo.AddDfm}

constructor TResourceInfo.Create(AOwner: TComponent);
begin
  inherited;

  FActive := False;
  FDfms := TList.Create;
  FModule := 0;
end; {TResourceInfo.Create}

destructor TResourceInfo.Destroy;
begin
  Clear;
  FDfms.Free;

  inherited;
end; {TResourceInfo.Destroy}

function CB_EnumDfmNameProc(hModule: THandle; lpszType, lpszName: PChar; lParam: Integer): Boolean; stdcall;
var
  ms: TMemoryStream;
  rs: TResourceStream;
  Buffer: array of Byte;
begin
  with TResourceInfo(lParam) do
    begin
      rs := TResourceStream.Create(TResourceInfo(lParam).Module, lpszname, lpszType);
      try
        ms := TMemoryStream.Create;
        try
          try
            SetLength(Buffer, 4);
            rs.Read(Buffer[0], SizeOf(Buffer));
            if string(Buffer) = 'TPF0' then
              begin
                rs.Seek(0, 0);
                ObjectBinaryToText(rs, ms);
                ms.Seek(0, 0);
                AddDfm(StrPas(lpszName), ms);
              end;
          except
            raise;
          end;
        finally
          ms.Free;
        end;
      finally
        rs.free;
      end;
    end;

  Result := True;
end; {CB_EnumDfmNameProc}

procedure TResourceInfo.EnumDfmNames;
begin
  if FModule > 0 then
    EnumResourceNames(FModule, RT_RCDATA, @CB_EnumDfmNameProc, Integer(Self));
end; {TResourceInfo.EnumDfmNames}

procedure TResourceInfo.DeleteDfm(const Name: string);
var
  i: Cardinal;
begin
  if FDfms.Count > 0 then
    for i := Pred(FDfms.Count) downto 0 do
      if UpperCase(TDfm(FDfms[i]).Name) = UpperCase(Name) then
        begin
          FDfms.Delete(i);
          Break;
        end;
end; {TResourceInfo.DeleteDfm}

procedure TResourceInfo.SetActive(const Value: Boolean);
begin
  if FActive <> Value then
    begin
      if Value then
        begin
          if FModule > 0 then
            FreeLibrary(FModule);

            (* LOAD_LIBRARY_AS_DATAFILE
               If this value is given, the function does a simple mapping of the file into the
               address space. Nothing is done relative to executing or preparing to execute the
               code in the mapped file. The function loads the module as if it were a data file.
               You can use the module handle that the function returns in this case with the Win32
               functions that operate on resources. Use this flag when you want to load a DLL in
               order to extract messages or resources from it, and have no intention of executing
               its code.If this value is not given, the function maps the file into the address
               space in the manner that is normal for an executable module. The behavior of the
               function is then identical to that of LoadLibrary in this regard. *)

          FModule := LoadLibraryEx(PChar(FExeFileName), 0, LOAD_LIBRARY_AS_DATAFILE);
          if not (FModule >= 32) then
            raise Exception.CreateFmt(rsErrorLoadingExeFile, [FExeFileName]);
          if Assigned(FOnActivate) then
            FOnActivate(Self);
        end
      else
        begin
          Clear;
          if FModule > 0 then
            begin
              FreeLibrary(FModule);
              FModule := 0;
            end;
          if Assigned(FOnDeactivate) then
            FOnDeactivate(Self);
        end;
      FActive := Value;
    end;
end; {TResourceInfo.SetActive}

procedure TResourceInfo.SetExeFileName(const Value: TFileName);
begin
  if FExeFileName <> Value then
    FExeFileName := Value;
end; {TResourceInfo.SetExeFileName}

function TResourceInfo.GetDfms(Index: Cardinal): TDfm;
begin
  Result := TDfm(FDfms[Index]);
end; {TResourceInfo.GetDfms}

function TResourceInfo.GetDfmCount: Cardinal;
begin
  Result := FDfms.Count;
end; {TResourceInfo.GetDfmCount}

procedure TResourceInfo.Clear;
begin
  if FDfms.Count > 0 then
    while FDfms.Count > 0 do
      FDfms.Delete(0);
end; {TResourceInfo.Clear}

{ TDfm }

constructor TDfm.Create(AOwner: TResourceInfo);
begin
  inherited Create;

  FData := TMemoryStream.Create;
  FName := '';
  SetOwner(AOwner);
end; {TDfm.Create}

destructor TDfm.Destroy;
begin
  FData.Free;
  inherited;
end; {TDfm.Destroy}


function TDfm.SaveToFile(FileName: TFileName; Mode: TDfmMode): Boolean;

  function EndOfStream(Stream: TStream): Boolean;
  begin
    with Stream do
      Result := Position = Size;
  end; {EndOfStream}

var
  fs: TFileStream;
  ms: TMemoryStream;
  s: string;
  i, j: Byte;
begin
  fs := TFileStream.Create(FileName, fmCreate or fmShareExclusive);
  try
    FData.Seek(0, 0);

    case Mode of
      dfmASCII:
        begin
          ms := TMemoryStream.Create;
          try
            s := FName + ' RCDATA' + #13#10 + '{';
            StreamLn(fs, s);

            ObjectTextToBinary(FData, ms);
            ms.Seek(0, 0);

            while not EndOfStream(ms) do
              begin
                s := '''';

                for i := 0 to 15 do
                  begin
                    if ms.Read(j, SizeOf(j)) = 0 then
                      Break;
                    s := Concat(s, Format('%2.2x', [j]));
                    if (i = 15) or EndOfStream(ms) then
                      s := Concat(s, '''')
                    else
                      s := Concat(s, ' ');
                  end;

                if EndOfStream(ms) then
                  s := Concat(s, #13#10 + '}');
                StreamLn(fs, s);
              end;

          finally
            ms.Free;
          end;
        end;

      dfmBinary:
        ObjectTextToBinary(FData, fs);
    end;

  finally
    fs.Free;
  end;
end; {TDfm.SaveToFile}

procedure TDfm.SetName(const Value: string);
begin
  if FName <> Value then
    FName := Value;
end; {TDfm.SetName}

procedure TDfm.SetOwner(const Value: TResourceInfo);
begin
  FOwner := Value;
end; {TDfm.SetOwner}

end.

请帮助,我非常感谢任何建议

1 个答案:

答案 0 :(得分:0)

I did not test this, so use it at your own risk, but try the following:

procedure StreamLn(AStream: TSTream; const S: string);
var
  SU: UTF8String;
begin
  SU := UTF8String(S) + #13#10;
  AStream.WriteBuffer(SU[1], Length(SU));
end;

That will write the string to the buffer in UTF-8 format, the most usual in these situations. I assume you don't want to write UTF-16 directly to the stream.