![]() |
GetLocaleInfo() Aufruf, ist es so richtig?
Hallo, ich würde mich gerne absichern ob folgender Code korrekt ist:
Delphi-Quellcode:
Ziel soll sein das ich in einem String das/die Zeichen für's Lokale Tausender-Trennzeichen bekomme.
function ThousandSeparator : String;
var buf: PChar; // temp puffer begin Result := '#'; // falsch initialisieren, gegebenfalls später mit einem Default-Wert bei Fehler ersetzen try buf := StrAlloc(10); // puffer eine größe zusichern GetLocaleInfo( LOCALE_SYSTEM_DEFAULT, LOCALE_STHOUSAND, buf, 10); // GetLocaleInfo() direkt abfragen ohne die Länge vom Trennzeichen zu kennen, aber über 10 sollten es wohl nicht werden finally Result := StrPas(buf); // in einen String konvertieren StrDispose(buf); // speicher bereinigen end; end; Oder ist es generell so falsch und es gibt aktuellere Methoden um das Zeichen (als String) zu bekommen? |
AW: GetLocaleInfo() Aufruf, ist es so richtig?
Zitat:
![]() Ansonsten noch zum WinAPI Ansatz: "Theoretisch" kann
Delphi-Quellcode:
fehlschlagen. In diesem Falle läuft dein
StrAlloc
Delphi-Quellcode:
im
StrDispose
Delphi-Quellcode:
Block ins Leere. Und die fixe Länge von 10 wird sicherlich auch funktionieren, aber korrekter wäre es die API einmal mit
finally
Delphi-Quellcode:
Buffer und 0 Länge aufzurufen und den Rückgabewert zu verwenden. Alternativ einen fixen Anfangsbuffer, Rückgabe prüfen,
nil
![]()
Delphi-Quellcode:
prüfen, Buffer verdoppeln, Aufruf wiederholen, etc.
ERROR_INSUFFICENT_BUFFER
|
AW: GetLocaleInfo() Aufruf, ist es so richtig?
Wäre es so korrekt? (mit Verzicht auf WinApi)
Delphi-Quellcode:
Muss ich da noch Speicher bereinigen?
function ThousandSeparator : String;
var FS: TFormatSettings; begin FS := TFormatSettings.Create; Result := FS.ThousandSeparator; end; |
AW: GetLocaleInfo() Aufruf, ist es so richtig?
Zitat:
Delphi-Quellcode:
. Alternativ beinhaltet
record
Delphi-Quellcode:
auch die globale Variable
System.SysUtils
Delphi-Quellcode:
, die du direkt verwenden kannst.
FormatSettings
|
AW: GetLocaleInfo() Aufruf, ist es so richtig?
Zitat:
|
AW: GetLocaleInfo() Aufruf, ist es so richtig?
Nun aber hoffentlich Ok:
Delphi-Quellcode:
Vielen Dank für so schnelle Hilfe!
function ThousandSeparator : String;
begin Result := FormatSettings.ThousandSeparator; end; |
AW: GetLocaleInfo() Aufruf, ist es so richtig?
Jetzt noch alles in eine eigene Unit und alles ist sauber, schön und leicht erweiterbar (jedenfalls würde ich es so machen).
Delphi-Quellcode:
So eine ähnliche Unit habe ich. Grund für MyFormatSettings ist, weil ich FormatSettings überschreibe und immer noch die originalen Werte haben möchte.
unit MyUnitX;
interface type TUnitX = record private var MyFormatSettings: TFormatSettings; public class function ThousandSeparator : string; static; end; implementation var UnitX: TUnitX; class function TUnitX.ThousandSeparator : String; begin Result := FormatSettings.ThousandSeparator; end; initialization UnitX.MyFormatSettings := TFormatSettings.Create(GetUserDefaultLCID); |
AW: GetLocaleInfo() Aufruf, ist es so richtig?
Ich portiere gerade Code der auf System.ThousandSeperator aufbaute, kommt nur in einer Unit vor, hab da nun meine funktion drinn, klappte auch beim ersten Post, ich wollte mich nur absichern das ich da kein Fehler mache, da ich die WinApi Antwort leider nicht ganz Verstanden habe erschien mir das was ich Verstanden habe einfacher umzusetzen. :mrgreen:
[EDIT]Also das mit dem StrDispose() das es fehlschlagen könnte hab ich Verstanden aber den Rest noch nicht.[/EDIT] |
AW: GetLocaleInfo() Aufruf, ist es so richtig?
Zitat:
Delphi-Quellcode:
gehört vor das TRY
buf := StrAlloc(10); // puffer eine größe zusichern
und
Delphi-Quellcode:
gehört vor Finally oder hinter das End.
Result := StrPas(buf);
Falls StrAlloc knallt, führst du dennoch StrDispose aus, es knallt nochmal und verfälscht den eigentlichen Fehler und wenn es knallt, greifst du auch noch auf buf zu, was ebenfalls nicht gut ist. UND, diese API löst keine Exceptions aus, also hilft Try-Finally/Except garnichts. Und falls es doch knallt, dann hattest DU "buf" falsch/nicht initialisiert oder es ist so viel kaputt, dass eine Fehlerbehandlung eh sinnlos ist. (ist = war vorher schon) Zitat:
PS: Wenn ich Code als "Delphi/Pascal" implementiere, dann lasse ich das C-typische StrAlloc weg und nutzte einen passenden Delphi-String (AnsiString/UnicodeString/String) und das StrDispose macht Delphi für mich. Nach der API mit SetLength oder einem billigen PChar-Cast den String kürzen, falls der Inhalt doch kleiner war. Oder ich nutze ein statisches Char-Array und ![]() |
AW: GetLocaleInfo() Aufruf, ist es so richtig?
So war mein Ansatz nach Zacherl's erstem Post:
Delphi-Quellcode:
function ThousandSeparator : String;
var buf: PChar; begin Result := ','; // falls was schiefläuft einen default Wert buf := StrAlloc(10); if GetLastError() = ERROR_SUCCESS then if GetLocaleInfo( LOCALE_SYSTEM_DEFAULT, LOCALE_STHOUSAND, buf, 10) <> 0 then Result := StrPas(buf); if GetLastError() <> ERROR_INSUFFICIENT_BUFFER then StrDispose(buf); end; |
AW: GetLocaleInfo() Aufruf, ist es so richtig?
Nee das ist auch Murks :-D In etwa so müsste es aussehen:
Delphi-Quellcode:
var
Buffer: PChar; BufferLen: Integer; begin BufferLen := GetLocaleInfo(LOCALE_SYSTEM_DEFAULT, LOCALE_STHOUSAND, nil, 0); if (BufferLen = 0) then begin RaiseLastOSError; end; Buffer := StrAlloc(BufferLen); if (not Assigned(Buffer)) then begin raise EOutOfMemory.Create('StrAlloc failed'); end; try if (GetLocaleInfo(LOCALE_SYSTEM_DEFAULT, LOCALE_STHOUSAND, Buffer, BufferLen) <> BufferLen) then begin RaiseLastOSError; end; Result := StrPas(Buffer); finally StrDispose(Buffer); end; end; |
AW: GetLocaleInfo() Aufruf, ist es so richtig?
Was soll bei
Delphi-Quellcode:
denn schiefgehen?
Result := FormatSettings.ThousandSeparator;
|
AW: GetLocaleInfo() Aufruf, ist es so richtig?
Zitat:
Delphi-Quellcode:
im Falle eines vorher erfolglosen
StrDispose
Delphi-Quellcode:
s.
StrAlloc
|
AW: GetLocaleInfo() Aufruf, ist es so richtig?
Zitat:
Etwas Zufälliges und zwar "laut Definition" den Fehlercode irgendeiner WinAPI, welches davor als Letztes einen Fehler lieferte. Genau darum steht auch niemals "Ergebnis siehe GetLastError, sondern "prüfe Result und wenn was schief lief, dann siehe GetLastError". Zitat:
|
AW: GetLocaleInfo() Aufruf, ist es so richtig?
Danke nochmals für die korrekte Handhabung per Api @Zacherl, ich hatte den Ansatz eigentlich nur gepostet wegen voriger Aussage warum ich nicht auf Compiler-Meldungen achte, das hatte ich da auch wenn Code falsch ist :-)
|
AW: GetLocaleInfo() Aufruf, ist es so richtig?
Könnte man Dein Beispiel auch so abändern oder ginge dabei wieder etwas schief?
Delphi-Quellcode:
function ThousandSeparator : String;
const Default = ','; // Bei Fehler ein Default Wert nutzen um Meldungen zu überspringen var Buffer: PChar; BufferLen: Integer; begin BufferLen := GetLocaleInfo(LOCALE_SYSTEM_DEFAULT, LOCALE_STHOUSAND, nil, 0); if (BufferLen = 0) then begin Result := Default; System.SetLastError(ERROR_SUCCESS); Exit; // RaiseLastOSError; end; Buffer := StrAlloc(BufferLen); if (not Assigned(Buffer)) then begin Result := Default; System.SetLastError(ERROR_SUCCESS); Exit; // raise EOutOfMemory.Create('StrAlloc failed'); end; try if (GetLocaleInfo(LOCALE_SYSTEM_DEFAULT, LOCALE_STHOUSAND, Buffer, BufferLen) <> BufferLen) then begin Result := Default; if Assigned(Buffer) then StrDispose(Buffer); System.SetLastError(ERROR_SUCCESS); Exit; // RaiseLastOSError; end; Result := StrPas(Buffer); finally StrDispose(Buffer); end; end; |
AW: GetLocaleInfo() Aufruf, ist es so richtig?
Würde soweit funktionieren. Die extra Abfrage bezüglich String freigeben kannst du dir aber sparen, da der
Delphi-Quellcode:
Abschnitt in jedem Falle ausgeführt wird (selbst bei
finally
Delphi-Quellcode:
). Und
Exit
![]() |
AW: GetLocaleInfo() Aufruf, ist es so richtig?
Vielen Dank! Ich habe nun das Extra StrDispose() und die SetLastError() Aufrufe entfernt.
|
AW: GetLocaleInfo() Aufruf, ist es so richtig?
Abgesehn davon, dass
Delphi-Quellcode:
sowieso immer True geliefert hätte.
if Assigned(Buffer) then
Und zusammen mit dem Finally wäre StrDispose dann doppelt ausgeführt worden. Zitat:
IMHO wäre SUCCESS laut Definition somit falsch. |
AW: GetLocaleInfo() Aufruf, ist es so richtig?
Mit dem "System.SetLastError(ERROR_SUCCESS);" wollte ich halt Verhindern das aus dem Programm heraus irgendwelche Fehler-Meldungen aufploppen könnten wenn die Funktion ThousandSeparator aufgerufen wird.
Die Delphi Hilfe über RaiseLastOSError brachte mich darauf. Die Funktion soll nur ein Ergebnis abliefern aber nie einen Fehler, total transparent, so als ob es Sie nicht gibt. |
AW: GetLocaleInfo() Aufruf, ist es so richtig?
Da mich die Exit-Anweisungen in dem Code gestört haben, musste ich einfach den Source umschreiben. Jedes der Exits hätten einfach in ein else gepasst.
Dabei ist mir dann aufgefallen, dass der Source insgesamt noch einfacher geschrieben werden kann, wenn man den Default-Wert als erstes setzt und nur noch die die Sachen stehen lässt, die diesen verändern würden. Das SetLasteError habe ich auch weg gelassen, da ich die Notwendigkeit an der Stelle nicht erkennen kann. Dabei ist dann dieses bisschen Source übrig geblieben:
Delphi-Quellcode:
Der Source kann nach kürzer werden, wenn man die nicht notwendigen "begin" und "end" bei zwei der if-Abfragen weglässt.
function ThousandSeparator : String;
const Default = ','; // Bei Fehler ein Default Wert nutzen um Meldungen zu überspringen var Buffer: PChar; BufferLen: Integer; begin Result := Default; BufferLen := GetLocaleInfo(LOCALE_SYSTEM_DEFAULT, LOCALE_STHOUSAND, nil, 0); if (BufferLen > 0) then begin Buffer := StrAlloc(BufferLen); if Assigned(Buffer) then begin try if (GetLocaleInfo(LOCALE_SYSTEM_DEFAULT, LOCALE_STHOUSAND, Buffer, BufferLen) = BufferLen) then begin Result := StrPas(Buffer); end; finally StrDispose(Buffer); end; end; end; end; Zu SetLastError und RaiseLastOSError: Da hier ein Default-Wert gesetzt wird, sind diese beiden Anweisungen nicht erforderlich. Gäbe es keinen Default-Wert, könnte das Ergebnis undefiniert sein. Dann wären die Anweisungen möglicherweise sinnvoll. |
AW: GetLocaleInfo() Aufruf, ist es so richtig?
Danke für's Upgrade!
|
AW: GetLocaleInfo() Aufruf, ist es so richtig?
Liste der Anhänge anzeigen (Anzahl: 1)
Zitat:
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 07:31 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz