📄 unitresourcedetails.pas
字号:
unit unitResourceDetails;
interface
uses Windows, Classes, SysUtils;
type
TResourceDetails = class;
TResourceDetailsClass = class of TResourceDetails;
TResourceModule = class
private
fDirty : Boolean;
function GetDirty: Boolean;
protected
function GetResourceCount: Integer; virtual; abstract;
function GetResourceDetails(idx: Integer): TResourceDetails; virtual; abstract;
public
procedure DeleteResource (idx : Integer); virtual;
procedure InsertResource (idx : Integer; details : TResourceDetails); virtual;
function AddResource (details : TResourceDetails) : Integer; virtual;
function IndexOfResource (details : TResourceDetails) : Integer; virtual; abstract;
function GetUniqueResourceName (const tp : string) : string;
procedure SaveToStream (stream : TStream); virtual;
procedure LoadFromStream (stream : TStream); virtual;
procedure SaveToFile (const FileName : string); virtual;
procedure LoadFromFile (const FileName : string); virtual;
procedure SortResources; virtual;
function FindResource (const tp, Name : string; ALanguage : Integer) : TResourceDetails;
property ResourceCount : Integer read GetResourceCount;
property ResourceDetails [idx : Integer] : TResourceDetails read GetResourceDetails;
property Dirty : Boolean read GetDirty write fDirty;
procedure ClearDirty;
end;
//======================================================================
// TResourceDetails class
TResourceDetails = class
private
fParent : TResourceModule;
fData : TMemoryStream;
fCodePage : Integer;
fResourceLanguage: LCID;
fResourceName: string;
fResourceType: string;
fMemoryFlags : word; // Resource memory flags
fDataVersion, fVersion : DWORD; // Resource header version info
fCharacteristics : DWORD;
fTag: LongInt;
fDirty : Boolean;
// Resource header characteristics
protected
constructor Create (AParent : TResourceModule; ALanguage : Integer; const AName, AType : string; ASize : Integer; AData : pointer); virtual;
procedure InitNew; virtual;
procedure SetResourceName(const Value: string); virtual;
class function SupportsRCData (const AName : string; Size : Integer; data : Pointer) : Boolean; virtual;
class function SupportsData (Size : Integer; data : Pointer) : Boolean; virtual;
public
class function CreateResourceDetails (AParent : TResourceModule; ALanguage : Integer; const AName, AType : string; ASize : Integer; AData : pointer) : TResourceDetails;
class function GetBaseType : string; virtual;
constructor CreateNew (AParent : TResourceModule; ALanguage : Integer; const AName : string); virtual;
destructor Destroy; override;
procedure BeforeDelete; virtual;
procedure ChangeData (newData : TMemoryStream); virtual;
property Parent : TResourceModule read fParent;
property Data : TMemoryStream read fData;
property ResourceName : string read fResourceName write SetResourceName;
property ResourceType : string read fResourceType;
property ResourceLanguage : LCID read fResourceLanguage write fResourceLanguage;
property CodePage : Integer read fCodePage write fCodePage;
property Characteristics : DWORD read fCharacteristics write fCharacteristics;
property Version : DWORD read fVersion write fDataVersion;
property DataVersion : DWORD read fDataVersion write fDataVersion;
property MemoryFlags : WORD read fMemoryFlags write fMemoryFlags;
property Dirty : Boolean read fDirty write fDirty;
property Tag : LongInt read fTag write fTag;
end;
//======================================================================
// Global function definitions
procedure RegisterResourceDetails (resourceClass : TResourceDetailsClass);
procedure UnRegisterResourceDetails (resourceClass : TResourceDetailsClass);
function ResourceWideCharToStr(var wstr : PWideChar) : string;
procedure ResourceStrToWideChar (const s : string; var p : PWideChar);
function ResourceNameToInt (const s : string) : Integer;
function CompareDetails (p1, p2 : Pointer) : Integer;
implementation
var
registeredResourceDetails : array of TResourceDetailsClass;
registeredResourceDetailsCount : Integer = 0;
resourcestring
rstNoBaseType = 'Can''t register resource details class with no base type';
rstNoStreaming = 'Module doesn''t support streaming';
procedure RegisterResourceDetails (resourceClass : TResourceDetailsClass);
begin
if Length (registeredResourceDetails) = registeredResourceDetailsCount then
SetLength (registeredResourceDetails, Length (registeredResourceDetails) + 10);
registeredResourceDetails [registeredResourceDetailsCount] := resourceClass;
Inc (registeredResourceDetailsCount)
end;
procedure UnRegisterResourceDetails (resourceClass : TResourceDetailsClass);
var
i : Integer;
begin
i := 0;
while i < registeredResourceDetailsCount do
if registeredResourceDetails [i] = resourceClass then
begin
if i < Length (registeredResourceDetails) - 1 then
Move (registeredResourceDetails [i + 1], registeredResourceDetails [i], (Length (registeredResourceDetails) - i - 1) * sizeof (TResourceDetailsClass));
Dec (registeredResourceDetailsCount)
end
else
Inc (i)
end;
function ResourceWideCharToStr(var wstr : PWideChar) : string;
var
len : word;
begin
len := word (wstr^);
SetLength (result, len);
Inc (wstr);
WideCharToMultiByte(CP_ACP, 0, WStr, Len, PChar (Result), Len + 1, nil, nil);
Inc (wstr, len);
result := PChar (result);
end;
procedure ResourceStrToWideChar (const s : string; var p : PWideChar);
var
buffer : PWideChar;
len, size : word;
begin
len := Length (s);
size := (Length (s) + 1) * sizeof (WideChar);
GetMem (buffer, size);
try
MultiByteToWideChar (CP_ACP, 0, PChar (s), -1, buffer, size);
p^ := WideChar (len);
Inc (p);
Move (buffer^, p^, len * sizeof (WideChar));
Inc (p, len)
finally
FreeMem (buffer)
end
end;
(*----------------------------------------------------------------------*
| procedure ResourceNameToInt |
| |
| Get integer value of resource name (or type). Return -1 if it's |
| not numeric. |
*----------------------------------------------------------------------*)
function ResourceNameToInt (const s : string) : Integer;
var
isNumeric : Boolean;
i : Integer;
begin
isNumeric := Length (s) > 0;
for i := 1 to Length (s) do
if not (s [i] in ['0'..'9']) then
begin
isNumeric := False;
break
end;
if isNumeric then
Result := StrToInt (s)
else
Result := -1
end;
function CompareDetails (p1, p2 : Pointer) : Integer;
var
d1 : TResourceDetails;
d2 : TResourceDetails;
i1, i2 : Integer;
begin
d1 := TResourceDetails (p1);
d2 := TResourceDetails (p2);
i1 := ResourceNameToInt (d1.ResourceType);
i2 := ResourceNameToInt (d2.ResourceType);
if i1 >= 0 then
if i2 >= 0 then
Result := i1 - i2 // Compare two integer ids
else
Result := 1 // id1 is int, so it's greater than non-int id2
else
if i2 >= 0 then
Result := -1 // id2 is int, so it's less than non-int id1
else
// Compare two string resource ids
Result := CompareText (d1.ResourceType, d2.ResourceType);
if Result = 0 then // If they match, do the same with the names
begin
i1 := ResourceNameToInt (d1.ResourceName);
i2 := ResourceNameToInt (d2.ResourceName);
if i1 >= 0 then
if i2 >= 0 then
Result := i1 - i2
else
Result := 1
else
if i2 >= 0 then
Result := -1
else
Result := CompareText (d1.ResourceName, d2.ResourceName)
end
end;
procedure TResourceDetails.BeforeDelete;
begin
// Stub
end;
procedure TResourceDetails.ChangeData(newData: TMemoryStream);
begin
fData.Clear;
fData.CopyFrom (newData, 0);
end;
constructor TResourceDetails.Create(AParent: TResourceModule; ALanguage: Integer; const AName, AType: string; ASize: Integer;
AData: pointer);
begin
fParent := AParent;
fResourceLanguage := ALanguage;
fResourceName := AName;
fResourceType := AType;
fData := TMemoryStream.Create;
fData.Write (AData^, ASize)
end;
constructor TResourceDetails.CreateNew(AParent: TResourceModule;
ALanguage: Integer; const aName : string);
begin
fParent := AParent;
fResourceLanguage := ALanguage;
fResourceName := AName;
fResourceType := GetBaseType;
if Assigned (AParent) then
AParent.AddResource (Self);
fData := TMemoryStream.Create;
InitNew
end;
class function TResourceDetails.CreateResourceDetails(
AParent: TResourceModule; ALanguage: Integer; const AName,
AType: string; ASize: Integer; AData: pointer): TResourceDetails;
var
i : Integer;
begin
result := Nil;
if (Length (AType) > 0) and (AType [1] in ['0'..'9']) then
try
for i := 0 to registeredResourceDetailsCount - 1 do
if registeredResourceDetails [i].GetBaseType = AType then
begin
if (AType <> IntToStr (Integer (RT_RCDATA))) or registeredResourceDetails [i].SupportsRCData (AName, ASize, AData) then
begin
result := registeredResourceDetails [i].Create (AParent, ALanguage, AName, AType, ASize, AData);
break
end
end;
except
end;
if Result = nil then
try
for i := 0 to registeredResourceDetailsCount - 1 do
if registeredResourceDetails [i].SupportsData (ASize, AData) then
begin
result := registeredResourceDetails [i].Create (AParent, ALanguage, AName, AType, ASize, AData);
break
end;
except
end;
if result = Nil then
result := TResourceDetails.Create (AParent, ALanguage, AName, AType, ASize, AData)
end;
destructor TResourceDetails.Destroy;
begin
fData.Free;
inherited;
end;
class function TResourceDetails.GetBaseType: string;
begin
Result := '0';
end;
procedure TResourceDetails.InitNew;
begin
// Stub
end;
procedure TResourceDetails.SetResourceName(const Value: string);
begin
fResourceName := Value;
fDirty := True
end;
function TResourceModule.AddResource(details: TResourceDetails): Integer;
begin
result := -1
// Stub
end;
procedure TResourceModule.ClearDirty;
var
i : Integer;
begin
fDirty := False;
for i := 0 to ResourceCount - 1 do
ResourceDetails [i].Dirty := False
end;
procedure TResourceModule.DeleteResource(idx: Integer);
begin
fDirty := True;
ResourceDetails [idx].BeforeDelete;
end;
function TResourceModule.FindResource(const tp,
Name: string; ALanguage : Integer): TResourceDetails;
var
i : Integer;
begin
Result := nil;
for i := 0 to ResourceCount - 1 do
if (ResourceDetails [i].fResourceType = tp) and (ResourceDetails [i].fResourceName = Name) and (Integer (ResourceDetails [i].fResourceLanguage) = ALanguage) then
begin
Result := ResourceDetails [i];
break
end;
if not Assigned (result) then
for i := 0 to ResourceCount - 1 do
if (ResourceDetails [i].fResourceType = tp) and (ResourceDetails [i].fResourceName = Name) and (ResourceDetails [i].fResourceLanguage = 0) then
begin
Result := ResourceDetails [i];
break
end
end;
function TResourceModule.GetDirty: Boolean;
var
i : Integer;
begin
Result := fDirty;
if not fDirty then
for i := 0 to ResourceCount - 1 do
if ResourceDetails [i].Dirty then
begin
Result := True;
break
end
end;
function TResourceModule.GetUniqueResourceName(const tp: string): string;
var
i : Integer;
n, n1 : Integer;
details : TResourceDetails;
begin
n := 0;
for i := 0 to ResourceCount - 1 do
begin
details := ResourceDetails [i];
if details.ResourceType = tp then
begin
n1 := ResourceNametoInt (details.ResourceName);
if n1 > n then
n := n1
end
end;
Result := IntToStr (n + 1);
end;
procedure TResourceModule.InsertResource(idx: Integer;
details: TResourceDetails);
begin
// Stub
end;
(*----------------------------------------------------------------------*
| TResourceModule.LoadFromFile |
| |
| Load from a file. Not usually overriden. |
*----------------------------------------------------------------------*)
procedure TResourceModule.LoadFromFile(const FileName: string);
var
s : TFileStream;
begin
s := TFileStream.Create (FileName, fmOpenRead or fmShareDenyNone);
try
LoadFromStream (s);
finally
s.Free
end
end;
(*----------------------------------------------------------------------*
| TResourceModule.SaveToFile |
| |
| Save to file. This can be overriden but usually isn't as it |
| relies on SaveToStream, which must be. |
*----------------------------------------------------------------------*)
procedure TResourceModule.LoadFromStream(stream: TStream);
begin
raise Exception.Create (rstNoStreaming);
end;
procedure TResourceModule.SaveToFile(const FileName: string);
var
s : TFileStream;
begin
s := TFileStream.Create (FileName, fmCreate);
try
SaveToStream (s);
ClearDirty
finally
s.Free
end
end;
(*----------------------------------------------------------------------*
| TResourceDetails.SupportsData |
| |
| Can be overridden to support a custom resource class, where you can |
| determine the custom class from the data - eg. RIFF data, etc. |
*----------------------------------------------------------------------*)
class function TResourceDetails.SupportsData(Size: Integer;
data: Pointer): Boolean;
begin
Result := False; // stub
end;
class function TResourceDetails.SupportsRCData(const AName: string;
Size: Integer; data: Pointer): Boolean;
begin
Result := False; // stub
end;
procedure TResourceModule.SaveToStream(stream: TStream);
begin
raise Exception.Create (rstNoStreaming);
end;
procedure TResourceModule.SortResources;
begin
// Stub
end;
end.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -