Jump to content

Clément

Members
  • Content Count

    360
  • Joined

  • Last visited

  • Days Won

    4

Everything posted by Clément

  1. I'm also using DevExpress a lot and never experience such startup delay. I'm autocreating Main Form, and some data modules (image lists, skin controllers, and the like ) required for the whole lifetime of the application. I'm creating manually everything else, including the login form. I'm having a painting performance issue with their forms, especially with acrylic effect.
  2. Clément

    Updated Community Edition

    One can only hope Emb will keep the CE project alive! Some friends and ex-coworkers had to move to VS over the past few years are using CE to built secondary projects, mostly indoors, so no real revenue comes from it. The unexpected factor came from VS programmers that liked working with Delphi, and actually enjoyed programming. Last I heard from them, they were considering buying licenses for a second mainstream project. 4% annual increase is nothing compared to what we are going through here ( Brazil ). The exchange rate went from 4.3 to almost 6 in the past 10 months... Almost 40% increase, given that our salaries are frozen, and most companies are revising they contract fees downwards, it's already a problem. If you consider that Emb also increases the license value, it's not crazy to expect over 60% increase in an year. This makes even the professional SKU too expensive for ISV and small companies to afford. Several companies, either I worked for, or friends I worked with, won't move passed XE because Delphi ecosystem is too expensive. The value of the upgrade (XE to 10.x) + 3rd party components( XE to 10.x) + retesting (Changes since XE) is more expensive than the project budget itself, and I'm talking about almost an year project timeframe. Those moved for good to MS which offers more products for the same value ( not only language, but access to all Microsoft product line and support). There's still a lot of bureaucratic work to package good cost/benefit SKU. Delphi is still using the same SKU model for decades. Someone have to tell them the market had changed since then. Students and teachers must rediscover delphi. Managers must be confident the investment/product quality in Delphi will meet or exceed expectations. Not easy at all.
  3. Clément

    Manage overloaded IfThen functions

    Naming is very hard... I usually like to place similar functions together and just call it "dhsUtilsxxx". "dhs" is my company, so to avoid conflicts with other libraries. "Utils" is just lack of creativity. Could as well be "Lib" "xxx" : No comments For example: dhsUtilsCnd = record function iif<T>( aCond : Boolean; aTrue : T, aFalse : T ) : T; function NullIf<T>( A, NullValue : T ) : boolean; function Coalesce<T>( const aStr : TArray<T> ) : T; end; dhsUtilsMath = record function max<T>( a, b ; T ) : T; overload; function min<T>(a, b: T ) : T ; overload; function max<T>( const A : TArray<T> ) : T; overload; function min<T>( const A : TArray<T> ) : T; overload; end; dhsUtilsList = record end; And also is not always easy to place a function in the correct "utilsxxx" record. As I'm too lazy to write : dhsUtilsCond.iif<string>( SomeCondition, Expression, Expression ); It's quite readable if used as: var _ : dhsUtilsCond; begin _.iff<string>( ThereYouGo, 'Hello', 'World'); end;
  4. Clément

    Manage overloaded IfThen functions

    HOP: Hope oriented programming
  5. Clément

    Manage overloaded IfThen functions

    One can always hope.
  6. Clément

    Manage overloaded IfThen functions

    In a delphi class, record, or form I mean.
  7. Clément

    Manage overloaded IfThen functions

    Hi, I'm using another construction for simple types: iif<T>( aCond : boolean; aTrue : T; aFalse : T ) : T; function iif<T>( aCond : boolean; aTrue : T; aFalse : T ) : T; begin if aCond then Result := aTrue else Result := aFalse; end; No overloads, very easy to ready.... procedure SomeProcedure; begin a := iif<string>( aCond, 'Hello', 'World'); b := iif<integer>( aCond, 12, 0 ); end; As for ternary operators, it would be a nice addition. Couldn't it be written in ASM?
  8. Hi, The way your types are declared you most certainly will end up writing overloads or specific methods for each! Have you considered the possibility work with only one type of array? (TPoligonA) For example: TPoligon = Array of TPoint; T4Poligon = Array [1..4] of TPoint; TPoligonA = TArray<TPoint>; TForm17 = class(TForm) procedure FormCreate(Sender: TObject); private { Private declarations } public { Public declarations } function NewT4 : TPoligonA; function ProcessPoligon( const aPoligon : TPoligonA ) : Boolean; end; implementation function TForm17.NewT4: TPoligonA; begin SetLength(Result,4); end; function TForm17.ProcessPoligon(const aPoligon: TPoligonA): Boolean; begin end; NewT4 will return a zero base array.. Since you will loose delphi type checking and range checking, you will need to check if the array have 4 elements. But, you will work with a unique type, which is what you asked HTH
  9. Clément

    SQL Update

    Hi, Since you already know the values of :TRS, :INCOME and :OUTGO you can check for nulls before entering your update. SELECT .... INTO :TRS,:INCOME,:OUTGO; IF TRS is NULL then TRS = 0; if INCOME IS NULL then INCOME = 0; if OUTGO IS NULL then OUTGO = 0; STOCK = TRS + INCOME - OUTGO; UPDATE ITEMS SET TRS= :TRS, INCOME = :INCOME, OUTGO= :OUTGO, STOCK= :STOCK WHERE ITEMNO=:ITMNO; END I haven't checked the syntax, but you get the idea.
  10. Since your concern is about startup time, there's a very handy way to find the culprit: Comment your code. All the objects( data modules, forms, classes ) created before the "application.run" should be checked for "legacy code not required anymore" If your project starts creating only the main form, then check the constructor and show form. And don't be shy! comment everything! even assignments (you never know what a setter might be doing) You will find out some leftovers from the past, that made perfect sense last decade, that are no longer required. The library you are using are among the best in delphi ecosystem, but... since you mention IBObjects, and FireDac, are you sure there's no query being executed at startup? DB Stuff might usually be rather slow, specially if some event's are alive during startup!
  11. Clément

    Hex2Binary

    The code: {$APPTYPE CONSOLE} uses System.SysUtils, System.Classes, System.Diagnostics; //******************************************** // Constants to tune the benchmark performance const HexStringLength = 64; InputDataCount = 512; IterationCount = 20000; //***************************************************************** // David Heffernan's routine, with Move replace by Int64 assignment {$DEFINE ReplaceMoveWithInt64Assign} function HexToBinHeff(const HexValue: string): string; const BinaryValues: array [0..15] of string = ( '0000', '0001', '0010', '0011', '0100', '0101', '0110', '0111', '1000', '1001', '1010', '1011', '1100', '1101', '1110', '1111' ); var HexDigit: Char; HexDigitValue: Integer; Ptr: PChar; begin SetLength(Result, Length(HexValue) * 4); Ptr := Pointer(Result); for HexDigit in HexValue do begin case HexDigit of '0'..'9': HexDigitValue := Ord(HexDigit) - Ord('0'); 'a'..'f': HexDigitValue := 10 + Ord(HexDigit) - Ord('a'); 'A'..'F': HexDigitValue := 10 + Ord(HexDigit) - Ord('A'); else raise EConvertError.CreateFmt('Invalid hex digit ''%s'' found in ''%s''', [HexDigit, HexValue]); end; {$IFDEF ReplaceMoveWithInt64Assign} PInt64(Ptr)^ := PInt64(BinaryValues[HexDigitValue])^; {$ELSE} Move(Pointer(BinaryValues[HexDigitValue])^, Ptr^, 4 * SizeOf(Char)); {$ENDIF} Inc(Ptr, 4); end; end; function HexToBinHeff2(const HexValue: string): string; const BinaryValues: array [0..15] of string = ( '0000', '0001', '0010', '0011', '0100', '0101', '0110', '0111', '1000', '1001', '1010', '1011', '1100', '1101', '1110', '1111' ); var HexDigit: Char; HexDigitValue: Integer; Ptr: PChar; begin SetLength(Result, Length(HexValue) * 4); Ptr := Pointer(Result); for var i : integer := low(HexValue) to High( HexValue ) do begin case HexValue[i] of '0'..'9': HexDigitValue := Ord(HexValue[i]) - Ord('0'); 'a'..'f': HexDigitValue := 10 + Ord(HexValue[i]) - Ord('a'); 'A'..'F': HexDigitValue := 10 + Ord(HexValue[i]) - Ord('A'); else raise EConvertError.CreateFmt('Invalid hex digit ''%s'' found in ''%s''', [HexValue[i], HexValue]); end; {$IFDEF ReplaceMoveWithInt64Assign} PInt64(Ptr)^ := PInt64(BinaryValues[HexDigitValue])^; {$ELSE} Move(Pointer(BinaryValues[HexDigitValue])^, Ptr^, 4 * SizeOf(Char)); {$ENDIF} Inc(Ptr, 4); end; end; //************************ // Mahdi Safsafi's routine {$DEFINE ReplaceMoveWithInt64Assign} function HexToBinMahdi(const HexValue: string): string; type TChar4 = array [0 .. 3] of Char; PChar4 = ^TChar4; const Table1: array ['0' .. '9'] of TChar4 = ('0000', '0001', '0010', '0011', '0100', '0101', '0110', '0111', '1000', '1001'); Table2: array ['a' .. 'f'] of TChar4 = ('1010', '1011', '1100', '1101', '1110', '1111'); var HexDigit: Char; P: PChar4; begin SetLength(Result, Length(HexValue) * 4); P := PChar4(Result); for HexDigit in HexValue do begin case HexDigit of '0' .. '9': P^ := Table1[HexDigit]; 'a' .. 'f': P^ := Table2[HexDigit]; 'A' .. 'F': P^ := Table2[Chr(Ord(HexDigit) xor $20)]; else raise EConvertError.CreateFmt('Invalid hex digit ''%s'' found in ''%s''', [HexDigit, HexValue]); end; Inc(P); end; end; function HexToBinMahdi2(const HexValue: string): string; type TChar4 = array [0 .. 3] of Char; PChar4 = ^TChar4; const Table1: array ['0' .. '9'] of TChar4 = ('0000', '0001', '0010', '0011', '0100', '0101', '0110', '0111', '1000', '1001'); Table2: array ['a' .. 'f'] of TChar4 = ('1010', '1011', '1100', '1101', '1110', '1111'); var HexDigit: Char; P: PChar4; begin SetLength(Result, Length(HexValue) * 4); P := PChar4(Result); for var i: integer := low(HexValue) to high( HexValue ) do begin case HexValue[i] of '0' .. '9': P^ := Table1[HexValue[i]]; 'a' .. 'f': P^ := Table2[HexValue[i]]; 'A' .. 'F': P^ := Table2[Chr(Ord(HexValue[i]) xor $20)]; else raise EConvertError.CreateFmt('Invalid hex digit ''%s'' found in ''%s''', [HexValue[i], HexValue]); end; Inc(P); end; end; {$IFDEF CPUX86} //*********************** // Kas Ob's asm32 version procedure CharToBin_ASM32(HexChar: Char; HexBuffer: PChar); asm push edi mov edi,edx // Get the decimal value of one Hex Char (= half byte) movzx eax, HexChar mov ecx, 57 sub ecx, eax sar ecx, 31 and ecx, 39 neg ecx add eax, ecx add eax, - 48 // Produce 4 Chars presenting 4 bits of HexChar xor ecx,ecx mov dx,$1 test al,4 cmovne cx,dx shl ecx,16 test al,8 cmovne cx,dx add ecx,$00300030 mov [edi],ecx xor ecx,ecx test al,1 cmovne cx,dx shl ecx,16 test al,2 cmovne cx,dx add ecx,$00300030 mov [edi+4],ecx pop edi end; function HexToBinAsm32(const HexValue: string): string; var HexDigit: Char; Ptr: PChar; begin SetLength(Result, Length(HexValue) * 4); Ptr := Pointer(Result); for HexDigit in HexValue do begin case HexDigit of '0'..'9','a'..'f','A'..'F': CharToBin_ASM32(HexDigit, Ptr); else raise EConvertError.CreateFmt('Invalid hex digit ''%s'' found in ''%s''', [HexDigit, HexValue]); end; Inc(Ptr, 4); end; end; function HexToBinAsm322(const HexValue: string): string; var HexDigit: Char; Ptr: PChar; begin SetLength(Result, Length(HexValue) * 4); Ptr := Pointer(Result); for var i: integer := low(HexValue) to High( HexValue ) do begin case HexValue[i] of '0'..'9','a'..'f','A'..'F': CharToBin_ASM32(HexValue[i], Ptr); else raise EConvertError.CreateFmt('Invalid hex digit ''%s'' found in ''%s''', [HexDigit, HexValue]); end; Inc(Ptr, 4); end; end; //********************* // Kas Ob's xmm version procedure CharToBin_XMM(HexChar: Char; HexBuffer: PChar); const DEC_TO_BIN_WORD_MASK: array[0..7] of UInt16 = ($01, $02,$00,$00, $04, $08, $00, $00); DEC_TO_BIN_FF_TO_CHARONE_DISTANCE: array[0..7] of UInt16 = ($FFCF, $FFCF, $FFCF, $FFCF, $FFCF, $FFCF, $FFCF, $FFCF); DEC_TO_BIN_REVERSE_MASK: array[0..15] of Byte = (10, $80, 8, $80, 2, $80, 0, $80, $80, $80, $80, $80, $80, $80, $80, $80); asm movzx eax, HexChar mov ecx, 57 sub ecx, eax sar ecx, 31 and ecx, 39 neg ecx add eax, ecx add eax, - 48 // Produce 4 Chars presenting 4 bits of HexChar movd xmm0, eax pxor xmm1, xmm1 movdqu xmm2, DEC_TO_BIN_FF_TO_CHARONE_DISTANCE movdqu xmm3, DEC_TO_BIN_WORD_MASK movdqu xmm4,DEC_TO_BIN_REVERSE_MASK punpckldq xmm0, xmm0 packssdw xmm0, xmm0 pand xmm0, xmm3 pcmpeqw xmm0, xmm1 psubw xmm0, xmm2 PSHUFB xmm0, xmm4 // reverse the result movq qword ptr[HexBuffer], xmm0 end; function HexToBinXmm(const HexValue: string): string; var HexDigit: Char; Ptr: PChar; begin SetLength(Result, Length(HexValue) * 4); Ptr := Pointer(Result); for HexDigit in HexValue do begin case HexDigit of '0'..'9','a'..'f','A'..'F': CharToBin_XMM(HexDigit, Ptr); else raise EConvertError.CreateFmt('Invalid hex digit ''%s'' found in ''%s''', [HexDigit, HexValue]); end; Inc(Ptr, 4); end; end; function HexToBinXmm2(const HexValue: string): string; var HexDigit: Char; Ptr: PChar; begin SetLength(Result, Length(HexValue) * 4); Ptr := Pointer(Result); for var i : integer := low( HexValue ) to high( HexValue) do begin case HexValue[i] of '0'..'9','a'..'f','A'..'F': CharToBin_XMM(HexValue[i], Ptr); else raise EConvertError.CreateFmt('Invalid hex digit ''%s'' found in ''%s''', [HexValue[i], HexValue]); end; Inc(Ptr, 4); end; end; {$ENDIF} //*************** // Benchmark code function RandomHexDigit: Char; var Ordinal: Integer; begin Ordinal := Random(16); case Ordinal of 0..9: Result := Chr(Ord('0') + Ordinal); 10..15: Result := Chr(Ord('a') + Ordinal - 10); else raise Exception.Create(''); end; end; function RandomHexString(Length: Integer): string; var Index: Integer; begin SetLength(Result, Length); for Index := 1 to Length do Result[Index] := RandomHexDigit; end; procedure TestCorrectness; var Index: Integer; HexStr, BinStr: string; begin for Index := 0 to $fffff do begin HexStr := IntToHex(Index, 6); BinStr := HexToBinHeff(HexStr); if BinStr<>HexToBinMahdi(HexStr) then raise Exception.Create('incorrect implementation'); if BinStr<>HexToBinMahdi2(HexStr) then raise Exception.Create('incorrect implementation'); if BinStr<>HexToBinHeff2(HexStr) then raise Exception.Create('incorrect implementation'); if BinStr<>HexToBinAsm32(HexStr) then raise Exception.Create('incorrect implementation'); if BinStr<>HexToBinAsm322(HexStr) then raise Exception.Create('incorrect implementation'); if BinStr<>HexToBinXmm(HexStr) then raise Exception.Create('incorrect implementation'); if BinStr<>HexToBinXmm2(HexStr) then raise Exception.Create('incorrect implementation'); end; end; procedure Benchmark; var Index, Iteration: Integer; sw: TStopwatch; HexStrings: TArray<string>; binaryString: string; begin SetLength(HexStrings, InputDataCount); for Index := 0 to InputDataCount-1 do HexStrings[Index] := RandomHexString(HexStringLength); sw := TStopwatch.StartNew; for Iteration := 0 to IterationCount-1 do for Index := 0 to InputDataCount-1 do begin binaryString := HexToBinHeff(HexStrings[Index]); binaryString := ''; // force a reallocation of the string every iteration of this loop end; Writeln('Pascal lookup (Heff): ', sw.ElapsedMilliseconds); sw := TStopwatch.StartNew; for Iteration := 0 to IterationCount-1 do for Index := 0 to InputDataCount-1 do begin binaryString := HexToBinMahdi(HexStrings[Index]); binaryString := ''; // force a reallocation of the string every iteration of this loop end; Writeln('Pascal lookup (Mahdi): ', sw.ElapsedMilliseconds); {$IFDEF CPUX86} sw := TStopwatch.StartNew; for Iteration := 0 to IterationCount-1 do for Index := 0 to InputDataCount-1 do begin binaryString := HexToBinAsm32(HexStrings[Index]); binaryString := ''; // force a reallocation of the string every iteration of this loop end; Writeln('asm32: ', sw.ElapsedMilliseconds); sw := TStopwatch.StartNew; for Iteration := 0 to IterationCount-1 do for Index := 0 to InputDataCount-1 do begin binaryString := HexToBinXmm(HexStrings[Index]); binaryString := ''; // force a reallocation of the string every iteration of this loop end; Writeln('xmm: ', sw.ElapsedMilliseconds); {$ENDIF} sw := TStopwatch.StartNew; for Iteration := 0 to IterationCount-1 do for Index := 0 to InputDataCount-1 do begin binaryString := HexToBinHeff2(HexStrings[Index]); binaryString := ''; // force a reallocation of the string every iteration of this loop end; Writeln('Pascal lookup (Heff2): ', sw.ElapsedMilliseconds); sw := TStopwatch.StartNew; for Iteration := 0 to IterationCount-1 do for Index := 0 to InputDataCount-1 do begin binaryString := HexToBinMahdi2(HexStrings[Index]); binaryString := ''; // force a reallocation of the string every iteration of this loop end; Writeln('Pascal lookup (Mahdi2): ', sw.ElapsedMilliseconds); {$IFDEF CPUX86} sw := TStopwatch.StartNew; for Iteration := 0 to IterationCount-1 do for Index := 0 to InputDataCount-1 do begin binaryString := HexToBinAsm322(HexStrings[Index]); binaryString := ''; // force a reallocation of the string every iteration of this loop end; Writeln('asm32 2: ', sw.ElapsedMilliseconds); sw := TStopwatch.StartNew; for Iteration := 0 to IterationCount-1 do for Index := 0 to InputDataCount-1 do begin binaryString := HexToBinXmm2(HexStrings[Index]); binaryString := ''; // force a reallocation of the string every iteration of this loop end; Writeln('xmm 2: ', sw.ElapsedMilliseconds); {$ENDIF} end; begin try Randomize; TestCorrectness; Benchmark; except on E: Exception do Writeln(E.ClassName, ': ', E.Message); end; Readln; end. The output: Pascal lookup (Heff): 5416 Pascal lookup (Mahdi): 5097 asm32: 8073 xmm: 6325 Pascal lookup (Heff2): 4487 Pascal lookup (Mahdi2): 4179 asm32 2: 7260 xmm 2: 5658
  12. Clément

    Hex2Binary

    Hi, Just would like to say thank you for this thread!!!! If I might just add my 0.00002c..... The "for in" syntax is not optimization friendly ... I ran the benchmark in my very slow machine with the following modification in Mahdi code: function HexToBinMahdi2(const HexValue: string): string; type TChar4 = array [0 .. 3] of Char; PChar4 = ^TChar4; const Table1: array ['0' .. '9'] of TChar4 = ('0000', '0001', '0010', '0011', '0100', '0101', '0110', '0111', '1000', '1001'); Table2: array ['a' .. 'f'] of TChar4 = ('1010', '1011', '1100', '1101', '1110', '1111'); var HexDigit: Char; P: PChar4; begin SetLength(Result, Length(HexValue) * 4); P := PChar4(Result); for var i: integer := low(HexValue) to high( HexValue ) do begin case HexValue[i] of '0' .. '9': P^ := Table1[HexValue[i]]; 'a' .. 'f': P^ := Table2[HexValue[i]]; 'A' .. 'F': P^ := Table2[Chr(Ord(HexValue[i]) xor $20)]; else raise EConvertError.CreateFmt('Invalid hex digit ''%s'' found in ''%s''', [HexValue[i], HexValue]); end; Inc(P); end; end; Pascal lookup (Heff): 5391 Pascal lookup (Mahdi): 5072 Pascal lookup (Mahdi2): 4184 asm32: 8067 xmm: 6369 I know the test is about the conversion, but since "for in" is very slow, it might help straight things up a little extra bit
  13. Clément

    No C/S FireDac for Delphi Professional

    Embarcadero should revisit their SKU matrix. Professional SKU is not satisfactory for DB Access, and some basic "Enterprise" software integration SOAP, REST etc Enterprise SKU is great for DB Access, but lack support for standard enterprise solution. Support for SOAP,REST, Encryption is very weak in native Enterprise SKU, and to offer a solution as good as native competition SKU you have to buy expensive 3rd party library. .NET offers such wide range of very good written library. This makes delphi ecosystem expensive. In Brazil we still have a very large base of Delphi Developers, they need a _good_ Professional SKU as most of them are ISV and don't have budget to buy an enterprise SKU especially if they won't use all the enterprise matrix features. This is also true for Managers in small companies. They won't spend money on features they won't need/use. Not an easy solution.
  14. Clément

    Reading fields with different lenghts

    Hi, Showing some code always helps us give accurate answers. Anyway.... If you can read Sizeof(TMyData) in one peace, you could use a record like type TMyData = record bSTX : Byte; bSep1: byte; Field1: Array[0..1] of byte; bSep2 : Byte; Field2 : Array[0..5] of byte; bSep3: Byte; Field3 : Array[0..2] of byte. Field4 : Array[0..4] of byte; bsep4 : Byte; bETX : Byte; bLRC : byte; end; var MyData : TMyData; begin fillchar( MyData, Sizeof(TMyData) , 0 ); move( DataFromCOM[0], MyData[0], Sizeof(TMyData) ); // Use the data MyData.Field1; MyData.Field2; end; Always check if you are receiving the expected number of bytes. Check the values of STX, ETX and the separators to see if at least those are Ok. If this routine will be called "a lot", I suggest creating MyData as a class field, to be use as long as the class is not destroyed.
  15. Hi, I'm revisiting the application I wrote to help me manage my applications localization, but after seeing all the nice work done in better translation manager... I'm puzzled.. Should I continue with my interface, or move to BTM? So here I am....I need to know how I can duplicate some features my implementation has. Basically my application generates a global class (glbLocalization) that I include in my projects. I can access all the localization properties I require. For example: glbLocalization.FormLogin.btnLogin.caption( aLanguageID : Cardinal = 0 ) When LanguageID is 0, the user default kicks in, which means, can be windows language, or any other language the user wants to be its default. There is a feature that my customers are very used too: Multi language UI. Basically this features allows the user to do whatever localization combination he likes: * The application remains in the main language, reports can be generated in any other languages. * Any form can be opened in different languages. Ex: All the user interface is in portuguese. The reports can be viewed in portuguese and mailed to a Brazilian manager, switch to any other supported language and email the report directlly The user might need to share some information available on his form with another user in LA, He opens another form in Spanish and share the contents. The implementation became trivial since I just have pass the LanguageID as the parameter ( to a form, report, etc) and everything is retrieved from the corresponding resource. To achieve this I generate a single resource file (.RC) with all the supported languages and translation. Given the LanguageID, it's a matter to go the corresponding section and get the string. Delphi's RTL resources (aka ResourceString) are not translated, it's a feature I would like to add in this new version. Back in Borland era, when I studied delphi translation features, I haven't found a way to implement the above features. Is there a way to use BTM (or delphi native localization) to mimic the above feature?
  16. Hi, I finally reached a Beta version of the utility I'm rewriting to help me manage my application localization. Since I talked about it here, I thought I could share some screens to give you an idea of this tool. I'm using mustache templates to generate the output, in theory the utility can generate code for any language. The generation process creates a JSON containing the translations that is merged with the templates. For the .RC and Delphi I using the following templates: .RC: {{#constants}} #define {{name}} {{value}} {{/constants}} {{#resources}} STRINGTABLE LANGUAGE {{language}}, {{subLanguage}} BEGIN {{#stringTable}} {{{name}}} "{{{value}}}" {{/stringTable}} END {{/resources}} .PAS (part of it): unit app.localization; interface uses WinAPI.Windows; const {{#languages}} {{constantName}} = {{languageID}}; {{/languages}} // --------------- {{#constants}} {{name}} = {{value}}; {{/constants}} function _( const StringID : DWORD; aLanguageID : DWORD = 0 ) : String; procedure SetDefaultLanguage( aLanguageID : DWord ); implementation {$R {{outputRES}}} var gDefaultLanguage : DWord; procedure SetDefaultLanguage( aLanguageID : DWord ); begin gDefaultLanguage := aLanguageID; end; function StringTableRes(hInstLib: Cardinal; idString: DWORD; wLang: Word): String; This is the generate .PAS: unit app.localization; interface uses WinAPI.Windows; const _EN_US = 1033; _PT_BR = 1046; _EL_GR = 1032; // --------------- GLOBAL_CPTN_BTN_OK = 1; GLOBAL_CPTN_BTN_APPLY = 2; GLOBAL_CPTN_BTN_CANCEL = 3; GLOBAL_CPTN_BTN_PRINT = 4; GLOBAL_CPTN_BTN_EXPORT = 5; GLOBAL_CPTN_BTN_FILTER = 6; GLOBAL_CPTN_GB_SAMPLEDATA = 7; GLOBAL_TXT_SAMPLE_DESCRIPTION = 8; FORMLOGIN_CPTN_WELCOME = 9; function _( const StringID : DWORD; aLanguageID : DWORD = 0 ) : String; procedure SetDefaultLanguage( aLanguageID : DWord ); implementation {$R teste.res} var gDefaultLanguage : DWord; procedure SetDefaultLanguage( aLanguageID : DWord ); begin gDefaultLanguage := aLanguageID; end; Let me show you the result: The code: implementation uses app.localization; {$R *.dfm} procedure TForm1.DoLocalize; begin GroupBox1.Caption := _( GLOBAL_CPTN_GB_SAMPLEDATA, _EN_US ); GroupBox2.Caption := _( GLOBAL_CPTN_GB_SAMPLEDATA, _PT_BR ); GroupBox3.Caption := _( GLOBAL_CPTN_GB_SAMPLEDATA, _EL_GR ); btnOK.Caption := _( GLOBAL_CPTN_BTN_APPLY, _EN_US ); btnOk1.Caption := _( GLOBAL_CPTN_BTN_APPLY, _PT_BR ); btnOk2.Caption := _( GLOBAL_CPTN_BTN_APPLY, _EL_GR ); btnCancel.Caption := _( GLOBAL_CPTN_BTN_CANCEL, _EN_US ); btnCancel1.Caption := _( GLOBAL_CPTN_BTN_CANCEL, _PT_BR ); btnCancel2.Caption := _( GLOBAL_CPTN_BTN_CANCEL, _EL_GR ); label1.caption := _( GLOBAL_TXT_SAMPLE_DESCRIPTION, _EN_US ); label2.caption := _( GLOBAL_TXT_SAMPLE_DESCRIPTION, _PT_BR ); label3.caption := _( GLOBAL_TXT_SAMPLE_DESCRIPTION, _EL_GR ); end; procedure TForm1.DoShow; begin DoLocalize; inherited; end; And the generator
  17. TBytes and pointers! Either love or hate them! Can you avoid allocation if you work with one large chuck of data (eg: 1 or 2MBytes) ?
  18. I liked BTM but I was afraid you would say that. I will have to keep my interface then. Anyway, thanks for that great tool!
  19. Clément

    Recomended Translation API

    Hi, I'm finalizing the modernization of my old translation IDE, and I need to update some features, like automated translation. The app is still using old API call. And at that time they were free. Before writing a Google or Microsoft API I would like to check if there's a better option for us developers. Is there any API you would recommend? Is there a more suitable API that translates better small application texts ( like button captions, form captions, etc ) Clément
  20. Clément

    Recomended Translation API

    Thank for the tips. Very nice job with BTM! I know how hard it is to manage a translation tool. When I decided to reinvent the wheel, there was no BTM, only the one provided by Inprise, or maybe Borland. I will look the source for inspiration, and as soon as mine is functional, I will post here some pictures, and hopefully you will help me with your invaluable insight. Clément
  21. Clément

    is the site infected?

    Hi, Usually IT departments install a lot of stuff to prevent infection, but once you're infected is another ball game. Check if your firewall is up and running. If you can install ( user permission wise ) a software in your machine, I strongly recommend you to download malwarebytes https://www.malwarebytes.com/ (Personal edition will be just fine ) from a clean machine, copy the installer to a pen-drive and install and run it in your machine. Let it run. Hopefully most of those nasty fellows can be removed. Unfortunately there's no "one antivirus to rule them all", so you might need some other antivirus software to clean it up. If your firewall is NOT active. turn off your machine at once. Don't waste time trying to put it back online, especially if you are in a LAN and have access to other machine in the network. Once windows reboots, your firewall should be up and running again. Don't use your machine without a firewall. If your firewall is deactivated again, shut it down for good and let the IT department deal with it HTH, Clément
  22. Clément

    10.4.1 Released today

    Just updated from 10.4 with Patch 1,2,3 applied. (WebInstall). No problems so far
  23. Clément

    RansomWare blues

    I got a [pgpopen@foxmail.com].pgp that forced me to reformat my machine. I have successfully installed 10.4, installed all components and libraries... loaded my project and ... I'm missing some VCL styles 😥 What happened to : [BRCC32 Error] dhsPinger.vrc(71): file not found: C:\Users\Public\Documents\Embarcadero\Studio\21.0\Styles\AquaLightSlate2.vsf [BRCC32 Error] dhsPinger.vrc(73): file not found: C:\Users\Public\Documents\Embarcadero\Studio\21.0\Styles\Glossy2.vsf [BRCC32 Error] dhsPinger.vrc(76): file not found: C:\Users\Public\Documents\Embarcadero\Studio\21.0\Styles\ZirconSE.vsf I installed all VCL Styles (GetIt Manager), went to DelphiStyles.com, search Embarcadero Blogs, CodeRage... where are those styles? Clément
  24. Clément

    RansomWare blues

    Hi, I'm still looking for the styles... I found this link, they are free, and yet nowhere to be found.. Shouldn't they be included in 10.4? I installed 10.2 and 10.3. The styles are not there ... They should be a free download in the getit manager... https://community.embarcadero.com/article/16642-getit-october-2018
  25. Hi, I wrote a Windows Service (REST HTTP Server) does a lot of stuff 😎. Several users (hopefully) will be connected and each might need to call this "app" from their own thread. Well, I would like to avoid compiling those modules into the main Service, because they will get changed a lot more often than the service itself. Some modules are specific to some users. A few details about this app: No form, no console no user interaction are required. I just need to pass a command line with some parameters ( 4 or 5 actually) and the "app" should run, do the thing, and return to the service. My options are: 1) Small executable with the required modules: ... just a log file to guide me (or my user). Will be called from the service with the required parameters (command line) 2) Write a DLL and load and unload it when there's an update (don't like the idea, but it works) 3) Write another Windows Service with the required modules. As both services share the same machine, communication between them should not be a problem. 4) Mix options 3 and 1 to build a powerfull architecture ( not required right now ). Do you guys have another option? A preferred one? TIA, Clément
×