-
Content Count
380 -
Joined
-
Last visited
-
Days Won
4
Everything posted by Clément
-
I would also register my methods. They all seems to have the same signature. unit Unit121; interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Generics.Collections, Vcl.StdCtrls; type TMyDecodeProcedure = procedure ( aDoc, aCdn, aRequestCorrelation, aMessageText : string ) of object; TForm121 = class(TForm) Button1: TButton; procedure FormCreate(Sender: TObject); procedure FormDestroy(Sender: TObject); procedure Button1Click(Sender: TObject); private { Private declarations } fDecoders : TDictionary<String, TMyDecodeProcedure >; procedure RegisterDecodeFunc; procedure DecodeExportAcc( aDoc, aCdn, aRequestCorrelation, aMessageText : string); procedure DecodeExportErr( aDoc, aCdn, aRequestCorrelation, aMessageText : string ); procedure DecodeExportReg( aDoc, aCdn, aRequestCorrelation, aMessageText : string ); public { Public declarations } function Execute( aDecoder, aDoc, aCdn, aRequestCorrelation, aMessageText : string; var aErrMsg : String ) : Boolean; end; var Form121: TForm121; implementation {$R *.dfm} procedure TForm121.FormCreate(Sender: TObject); begin fDecoders := TDictionary<String, TMyDecodeProcedure >.Create; RegisterDecodeFunc; end; procedure TForm121.FormDestroy(Sender: TObject); begin fDecoders.Free; end; procedure TForm121.DecodeExportAcc(aDoc, aCdn, aRequestCorrelation, aMessageText: string); begin // end; procedure TForm121.DecodeExportErr(aDoc, aCdn, aRequestCorrelation, aMessageText: string); begin // end; procedure TForm121.DecodeExportReg(aDoc, aCdn, aRequestCorrelation, aMessageText: string); begin // end; function TForm121.Execute(aDecoder, aDoc, aCdn, aRequestCorrelation, aMessageText: string; var aErrMsg : String): Boolean; var lDecoder : TMyDecodeProcedure; begin Result := fDecoders.TryGetValue(aDecoder, lDecoder); if Result then lDecoder( aDoc, aCdn, aRequestCorrelation, aMessageText ) else aErrMsg := Format('Decoder not found: %s', [aDecoder] ); end; procedure TForm121.RegisterDecodeFunc; begin fDecoders.Add('EXPREG', DecodeExportReg ); fDecoders.Add('EXPACC', DecodeExportAcc ); fDecoders.Add('EXPERR', DecodeExportErr ); { ... } end; procedure TForm121.Button1Click(Sender: TObject); var lErrMsg : String; begin lErrMsg := ''; Execute('EXPREG','1','2','3','4', lErrMsg); end; end. And you can add decoders more easily too..
-
FireDac has restrictions in Professional and Community edition. Check this: https://www.embarcadero.com/docs/rad-studio-feature-matrix.pdf
-
Dictionaries, Hashing and Performance
Clément posted a topic in Algorithms, Data Structures and Class Design
Actually I guess is the other way around! The more expert I get the more refactoring I do! As @Lars Fosdal said, cryptic code, WTF was I thinking code, Code that could benefit from modern RTL code if there's no performance penalty. For example: For lPair in SomeObjectList is slower than for i:= 0 to SomeobjectList.count-1. So I won't refactor it. Depending where the code is placed, I will use one form or the other. Replacing TStringList (used as dictionary) with a TDictionary/TDictionaryObject makes a huge diference!- 53 replies
-
- tdictionary
- tstringlist
-
(and 2 more)
Tagged with:
-
Migrating projects from Delphi to .Net
Clément replied to Mike Torrettinni's topic in Project Planning and -Management
How productive is you customer using you application? That's the question you should ask yourself. You can take whatever IDE you like... and what? Clone you exact application UI, behavior and functionality. All the fancy .NET stuff would still be under the hood. So.. what does he need.... exactly! Ah! He wants something new, which means something different. What exactly? less clicks? More "live" information on screen? Dashboards? Notifications? Users wants productivity. Developers wants fast time to market, One excludes the other -
Delphi 11.3 unusable due to full-build-requiring onslaught of F2084 "Internal Compiler Errors" from minor source modifications
Clément replied to PaulM117's topic in Delphi IDE and APIs
It doesn't seem to be a dproj or dpr related, but how old is your .dproj ? Have you create a new one for 11.x? Are all your .pas files in you dproj? if not, make sure your are deleting all dcus files manually prior to rebuild. For example, if you select "CLEAN" the IDE will delete only the files present in your dproj, you might get some old dcus in your built! If this is the case, third party dcus are the first you need to check. -
Hi, Is it possible to scan the content, downloaded using Edge Browse, for a specific text? I don't want to inject or alter anything. Just scan the page for a specific text. Can this be done with edgeBrowser? Is there a sample? TIA, Clément
-
Yeap! That did the trick. Thank you
-
Just downloaded and installed (WebInstall). I use the migration tool to backup and restore my settings. All my programs compiled without any errors, except, of course, those using VCL Styles from Get it. After downloading all the styles (again) they compiled just fine! Can't wait to see if the debugger got some love!
-
Hi, I'm using D11.2 and ICS 8.71 I'm working on a two-part project. Desktop application + Windows Service. All UI part is done in the Desktop Application. For example: I can set smtp server parameters within the Desktop application. The Service will get the smtp parameters and effectively send the email. The email can be sent by several triggers. For example: running low on disk space, a specific folder is larger than specified, etc.. For normal smtp accounts everything works smoothly! Here enters the OAuth2. If I understood correctly, OAuth2 requires a user intervention during the sending process, which in my case will happen in the service -> no UI -> no Browser! I was wondering if it's possible to "send the required data" from the Service, so the desktop could display the Browser and allow the user to interact, get the required information, and send it back to the service. Hopefully, this authentication will happen once or twice. Since it's possible for an external browser (different process than the application which send the mail ) to collect the data, and validate the application, I was wondering if it's possible to take things one step further, and send the data to the service. (I would not like to send an email from the Desktop Application, if it comes to that, I prefer having a separate application which would handle the authentication). In order to communicate properly, would it be possible to have IcsRestEmail in my Desktop Application, collect the data and get back to the service? procedure TSslSmtpTestForm.SslSmtpClientGetNewToken(Sender: TObject); { V8.65 } begin if NOT IcsRestEmail1.GetNewToken(True, Self) then // allow interaction, waits for broweser window to be completed, V8.71 added self Display('Failed to get OAuth2 Bearer Token') else begin if (Pos (IcsRestEmail1.NewAccEmail, SslSmtpClient.UserName) = 0) and (IcsRestEmail1.NewAccEmail <> '') then Display('OAuth2 Token for Wrong Account, Expected: ' + SslSmtpClient.Username + ', Got: ' + IcsRestEmail1.NewAccEmail) else begin SslSmtpClient.OAuthToken := IcsRestEmail1.AccToken; SslSmtpClient.TokenExpireDT := IcsRestEmail1.AccExpireDT; Display('Got New OAuth2 Bearer Token OK'); end; end; end; I should send a blocking IPC request from this event, wait until the user interacted, and return with OAuthToken and TokenExpireDT. How often would AccToken require renewing? It's seems a lot of work and the user might end up having email issues when the token expiration hits (probably on a Sunday) On the other hand, I use Thunderbird to send emails from my gmail account. And I did only once the validation process. Since my application is not Thunderbird, it might differ. Hopefully, it's possible to have some nice code written to solve this. Have you done such a thing? Is it even possible? Clément
-
Windows Service, gmail, and OAuth2 blues
Clément replied to Clément's topic in ICS - Internet Component Suite
I see. I can use the refresh token even if "some days" has passed? For example, some tasks might run over a weekend. I will use the refresh token on Sunday to send the last email, and only refresh it again next saturday before sending the first email. -
Windows Service, gmail, and OAuth2 blues
Clément replied to Clément's topic in ICS - Internet Component Suite
I will protect both ClientID and ClientKey in my desktop application. They will only get unprotected to assign the corresponding properties in IcsRestEmail. How is this call done? Are they transmitted to google protected? -
Windows Service, gmail, and OAuth2 blues
Clément replied to Clément's topic in ICS - Internet Component Suite
Just for clarification, I can use only IcsRestEmail in my desktop application. The user will enter it's account setting, and I will call "GetNewToken". If everthing works fine, I'll endup with AccToken and AccExpireDT assigned, and in my case I will store them in my database. Later, the service will read those parameter and send the mail ... this is great! Thanks! -
How to handle error 452 - 4.3.1 Insufficient system resources
Clément posted a topic in ICS - Internet Component Suite
Hi, I'm using ICS 8.68 and Delphi XE. This Windows Service checks for emails every minute, and send all emails that are found. The SMTP server is replying with 452 - 4.3.1 Insufficient system resources after a while. If my customer restart the service ( takes a little over a minute ), another batch of emails are sent without errors ( Same server, same port) Until I receive the error 452 again. From his point of view, my application has a problem, since a service restart solves the problem. From mine, the SMTP server, which might be shared with other applications, has some issues, either disk space or memory. The service does a lot of other things and all of them are working fine ( no errors in any log). Should I abort sending emails when this the SMTP server replies with this error? How can I trap it? TIA, Clément -
How to handle error 452 - 4.3.1 Insufficient system resources
Clément replied to Clément's topic in ICS - Internet Component Suite
The routine is working fine, and I really don't want to upset the protocol. I asked for this information. Unfortunately most IT folks are in holiday break. My best guess: this SMTP server is share among other applications. I'm placing a delay before the initial call to connect (or MailForm). -
How to handle error 452 - 4.3.1 Insufficient system resources
Clément replied to Clément's topic in ICS - Internet Component Suite
Sorry if I make it sound like was an ICS issue. It's an internal SMTP server ( I don't know which ). I ask their IT folks to help me with some information, but this time of the year emails must be sent, and since most IT fellows are in holidays.... Getting back to ICS, is there a "better" event to add some delay ( emails per hour throttle comes to my mind ) procedure TRNBWSMTP.SmtpRequestDone(Sender: TObject; RqType: TSmtpRequest; ErrorCode: Word); begin if not fDebugMode then Log(FSMTP.LastResponse); // This is where it logs the error 452 if (ErrorCode > 0) and (ErrorCode < 10000) then begin Log('RequestDone Rq=' + IntToStr(Ord(RqType)) + ' Error='+ FSMTP.ErrorMessage); if ErrorCode = 501 then begin FSuccess := false; FSMTP.Quit; exit; end; end; {...} end; -
Hi, Happy XMas! I must read a bunch o PNG images to my program and store them in a database. The pictures (PNG) have different height and width, and I must process them in order to keep all of them in 600x600. For example: I read a PNG image 704x404, I must cut 704 -> 600 and a must fill 404 -> 600 , without loosing transparency. I have some ideas of how to do it, but it must be "fast" and correct. Any ideas?
-
Delphi beta testing a "premium" privilege?
Clément replied to Brandon Staggs's topic in Tips / Blogs / Tutorials / Videos
Hi. I received this email yesterday " We are pleased to send to RAD Studio customers on Update Subscription this invite to join the beta program for Embarcadero’s next major release of Delphi, C++Builder, and RAD Studio, codenamed Malawi. This invitation is for all Update Subscription customers (after an initial beta invite limited to Premium Update Subscription customers only). This invite is personal and cannot be shared with other developers without an active Update Subscription. " Merry Christmas -
Hi, Is it possible to generate a "create table" script using Firedac? How about "Create Index"? Any sample? TIA, Clément
-
I looked the code and managed to build what I need. But I'm still not sure the code is correct. The only way I found is to derive from TFDTable like: TFDMyTable = Class( TFDTable ) public procedure GenerateSQLCreate( aGenerateDrop : Boolean; AParts: TFDPhysCreateTableParts; aResult : TStrings ); end; In order to get any result I must execute as: procedure TForm98.FormCreate(Sender: TObject); var lTable : TFDMyTable; begin lTable := TFDMyTable.Create(nil); try lTable.Connection := FDConnection1; lTable.TableName := 'Employees'; lTable.Open; lTable.Close; lTable.GenerateSQLCreate(true,[tpTable,tpGenerators,tpPrimaryKey,tpIndexes], Memo1.Lines); finally lTable.Free; end; end; If I don't "Open/Close" before calling "GenerateSQLCreate" I get an Access Violation try // Build Table from FieldDefs and IndexDefs CheckTable; // Access Violation here if I don't Open/Close before the call OpenIndexes; The table (lTable in this case) won't be attached to any visual components (like DBGrid or such). How many record will Open retrieve? In this case I really don't need any records, just metadata should be enough. Is there a method I should call that will only retrieve metadadata info? And the result is pretty cool! DROP TABLE Employees; CREATE TABLE Employees ( EmployeeID INT IDENTITY(1,1) NOT NULL, LastName NVARCHAR(20) NOT NULL, FirstName NVARCHAR(10) NOT NULL, Title NVARCHAR(30), TitleOfCourtesy NVARCHAR(25), BirthDate DATETIME2, HireDate DATETIME2, Address NVARCHAR(60), City NVARCHAR(15), Region NVARCHAR(15), PostalCode NVARCHAR(10), Country NVARCHAR(15), HomePhone NVARCHAR(24), Extension NVARCHAR(4), Photo VARBINARY(MAX), Notes NVARCHAR(MAX), ReportsTo INT, PhotoPath NVARCHAR(255) ); ALTER TABLE Employees ADD CONSTRAINT [PK_Employees] PRIMARY KEY (EmployeeID); CREATE INDEX LastName ON Employees (LastName, EmployeeID); CREATE INDEX PostalCode ON Employees (PostalCode, EmployeeID);
-
Overlap JPG photo to oa background transparently
Clément posted a topic in RTL and Delphi Object Pascal
Hi, My customer has a database with a lot of employee picture ( for smartcard tags). He wants to overlap each photo to a custom background. The idea is to trim out as much as possible the white rectangular background of the employee photo, leaving only his face, and then apply it over a custom background. What are my options? (All pictures and backgrounds are JPG) -
Overlap JPG photo to oa background transparently
Clément replied to Clément's topic in RTL and Delphi Object Pascal
Well.... It's cool enough! Here is the code I wrote. unit Unit40; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, jpeg, ExtCtrls, StdCtrls; type TForm40 = class(TForm) imgBackground: TImage; imgEmployee: TImage; imgOverlap: TImage; btnOverlap: TButton; procedure btnOverlapClick(Sender: TObject); private { Private declarations } public { Public declarations } end; var Form40: TForm40; implementation {$R *.dfm} type PRGB = ^TRGB; TRGB = record B : byte; G : Byte; R : Byte; end; function ColorBetween( Color : TRGB; I1, I2 : Byte ) : Boolean; begin result := (Color.R>=I1) and (Color.R<=I2) and (Color.G>=I1) and (Color.G<=I2) and (Color.B>=I1) and (Color.R<=I2); end; function IsWhitish(Color: TRGB): TRGB; begin if ColorBetween( Color, 210,255 ) then begin Color.R := 255; Color.G := 255; Color.B := 255; end; result := Color; end; procedure NormalizeWhite(Bitmap: TBitmap); var Row : integer; p : PRGB; Col : integer; begin for Row := 0 to Bitmap.Height-1 do begin p := PRGB(Bitmap.ScanLine[Row]); Col := Bitmap.Width; while (Col > 0) do begin p^ := IsWhitish(p^); inc(p); dec(Col); end; end; end; procedure TForm40.btnOverlapClick(Sender: TObject); var ldstBmp, lsrcBmp : TBitmap; i: Integer; j: Integer; begin lsrcBmp := TBitmap.Create; ldstBmp := TBitmap.Create; try // Loading employee picture with rectangular white background lsrcBmp.Assign(imgEmployee.Picture.Graphic); // Converting Whitish to White NormalizeWhite(lsrcBmp); // Loading destination background ldstBmp.Assign(imgBackground.Picture.Graphic); // Drawing employee picture over background transparently TransparentBlt( ldstBmp.Canvas.Handle, 50, 70 , lsrcBmp.Width, lsrcBmp.Height, lsrcBmp.Canvas.handle, 0, 0 , lsrcBmp.Width, lSrcBmp.Height, clWhite ); imgOverlap.Picture.Bitmap.Assign(ldstBmp); finally lsrcBmp.Free; ldstBmp.Free; end; end; end. The result is very cool. Thanks -
There are a few things to resolve before getting to "animal id". This is just an example using Delphi 11, but older version should work too. (Might need to remove the inline variable). This is how I would do it: unit Unit94; interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, System.JSON; type TForm94 = class(TForm) Button1: TButton; procedure Button1Click(Sender: TObject); private { Private declarations } const _JSON = ' {"result": [{ "animals": [{ "id":1, "name":"pig" } ] } ] }'; public { Public declarations } end; var Form94: TForm94; implementation {$R *.dfm} procedure TForm94.Button1Click(Sender: TObject); var lJsResult : TJsonObject; lJsResultArray : TJsonArray; lJsAnimals : TJsonObject; lJsAnimalArray : TJsonArray; lJsAnimal : TJsonObject; lId : Integer; lname : String; begin lJsResult := TJSONObject.ParseJSONValue(_JSON) as TJsonObject; try if lJsResult.TryGetValue<TJsonArray>('result', lJsResultArray) then begin for var r := 0 to lJsResultArray.Count-1 do begin lJsAnimals := lJsResultArray.Items[r] as TJsonObject; lJsAnimalArray := lJsAnimals.GetValue<TJsonArray>('animals'); for var i := 0 to lJsAnimalArray.Count-1 do begin lJsAnimal := lJsAnimalArray.Items[i] as TJSONObject; if not lJsAnimal.TryGetValue<Integer>('id', lId ) then raise Exception.Create('No "ID" Field'); if not lJsAnimal.TryGetValue<String>('name', lname) then raise Exception.Create('No "name" Field'); // DO something with lId, and name end; end; end finally lJsResult.Free; end; end;
-
Hi, How did you measure the performance of static arrays vs dynamic arrays? IME I found dynamic array to be faster than static arrays for large data. I almost always use static arrays for smallish data types. Be sure to allocate your dynamic array only once, and use it as you please. My $0.02 type THugeArray = TArray<Integer>; TForm90 = class(TForm) procedure FormCreate(Sender: TObject); private { Private declarations } Table2 : THugeArray; public { Public declarations } end; var Form90: TForm90; implementation {$R *.dfm} procedure TForm90.FormCreate(Sender: TObject); begin SetLength( Table2, MaxInt ); // Will take some time to allocate the memory. end;
-
Hi, Do you know if Delphi 11 has support for CryptSignMessage? If it doesn't is there a sample code to show me how can I sign a text file with PKCS7. TIA
-
Hi, In this project I need to ZIP huge text files ( over 1 GB ) for backup purposes. And I got disappointed. I'm using Delphi library and third party components but I can't beat windows vanilla zip, neither in speed nor in size. I am testing those libraries with 3 files: huge3.txt 1,926,179Kb, huge4.txt 797,946Kb and huge5.txt 650,767kb (You really don't want to ask the sizes of huge1 and huge2 ). Using windows (send compressed zip folder) in less then 2 minutes produces a 255,940KB zip files. Using delphi library (ZipForge, Abbrevia, VCL.Zip ) even at max compression level the best library produced a 316,690 KB. It took over 3 minutes. Needless to say my customer will not accept such difference. I don't really need to produce ZIP files, I can use any compression I like, but the file must be opened by a popular compressor viewer. Is there any hope?