Trotzdem stellt sich mir die Frage, wo der Vorteil ist? Die statische Klasse erstellt auch eine "globale" Variable, ja OK, nicht wirklich global, weil ich nur über die Klasse darauf zugreifen kann. Aber sie wird beim Start des Programmes über CreateClass erzeugt und erst beim Beenden des Programmes über DestroyClass wieder freigegeben und belegt somit für die komplette Laufzeit Speicher. Auch dann wenn die Klasse nur in irgendeinem Modul benötigt wird, das vielleicht gar nicht vom User verwendet wird. Gibt es da nicht eine elegantere Lösung für
API Callback-Funktionen, die nur dann Speicher belegen wenn sie aufgerufen werden, also ohne globale Variable?
Also, es wird ja lediglich der Speicher für ein dynamisches Array - also ein Pointer - verwendet. Das sind in 64-Bit gerade mal 8 Byte. Ich glaube kaum, dass das ins Gewicht fällt.
Hier ein alternativer Ansatz, der auch mehrere Threads berücksichtig. Basiert noch auf deinem ursprünglichen Code für die Formatierung. (Vermutlich nicht relevant, aber der Form halber: StrTo
UIntDef)
Delphi-Quellcode:
type
TCodePageEnumerator = class
strict private
class threadvar
CodePageNumbers: TList<Cardinal>;
class function EnumCodePagesProc(CodePage: PWideChar): Cardinal; static; stdcall;
strict protected
class function FormatCodePageName(AValue: Cardinal; const AName: string): string; virtual;
class function GetCodePageName(CP:Cardinal): String;
public
class procedure GetCodepageList(CodePageList: TStrings);
end;
class procedure TCodePageEnumerator.GetCodepageList(CodePageList: TStrings);
begin
CodePageNumbers := TList<Cardinal>.Create;
try
CodePageList.Clear;
EnumSystemCodePages(@EnumCodePagesProc, CP_SUPPORTED);
for var codePageNumber in CodePageNumbers do
begin
if codePageNumber > 0 then
CodepageList.Add(Format('%.5d: %s', [codePageNumber, GetCodePageName(codePageNumber)]));
end;
finally
CodePageNumbers.Free;
CodePageNumbers := nil;
end;
end;
class function TCodePageEnumerator.EnumCodePagesProc(CodePage: PWideChar): Cardinal;
Var
Cp: Cardinal;
begin
Result := 0;
if CodePageNumbers = nil then Exit;
if (CodePage <> Nil) then
begin
if (Length(CodePage) > 0) then
begin
Cp := StrToUIntDef(CodePage, 0);
if (Cp > 0) then
begin
CodePageNumbers.Add(Cp);
Result := 1;
end;
end;
end;
end;
class function TCodePageEnumerator.FormatCodePageName(AValue: Cardinal; const AName: string): string;
begin
Result := AName.Remove(0, AValue.ToString.Length + 1).TrimLeft.Trim(['(', ')']);
end;
class function TCodePageEnumerator.GetCodePageName(CP:Cardinal): String;
var CpInfoEx : TCPInfoEx;
begin
Result := '';
if IsValidCodePage(Cp) then
begin
GetCPInfoEx(Cp, 0, CpInfoEx);
Result := FormatCodePageName(CP, CpInfoEx.CodePageName);
end;
end;