Showing posts with label #Delphi. Show all posts
Showing posts with label #Delphi. Show all posts

Sunday, 22 October 2023

Use(s) less

- how to visualize your uses - for un-needed and wrong scoped units.

The "Uses" plugin installed and feed with a PAL report.

Disclaimer: Even if the above picture shows my usage of the code in the current state - the code/plugin is by no means done and complete - but I put this out for others to tinker with and benefit from.

One of the things that has been on my list of wish's for the Delphi IDE since forever, has been the ability to identify which units in your uses clause is either not needed, or should/could be moved from the interface section to the implementation section.

There seems to be good reasons for that feature not to be a 100% correct in it assumption in what is needed and what could be moved, and that might also be the reason Embarcadero has not included that feature yet, but..

I only need something that is good enough, and that can help me make the decision on what to clean up.

There are some third-party tools that attempt to do that, one being Peganza's Pascal Analyzer - and the free Lite version is sufficient to what I attempted to try here.

With the new CodeEditorEvents added to the OTAPI, it is now a lot easier to change the rendering of the code editor window in a safer way.

So this is what you need to do to get to a similar result - you need to download and install Pascal Analyzer (Lite).

Setup a project to handle your Delphi project, and you can optimizer the output from the analysis to only output the Uses.txt with only the Usage (USES1) - since that is the only needed.

I should mention that people more clever than me - could probably utilize the LSP or DelphiAST (or whatnot) - to make a more elegant solution - and they should :D.

So the prerequisite for the plugin is in place - a Uses.txt to parse. And to "refresh" the Uses.txt - you would have to run C:\Program Files\Peganza\Pascal Analyzer Lite\palcmd.exe <MyDocuments>\Pascal Analyzer Lite\Projects\<Myproject>.pap again.

The plugin contains code to parse Uses.txt and created a dictionary where each unit/module has a list of flagged units.

That dictionary is used to get the uses statements for the current unit, so that the renderer can either gray out or strikeout the unit name in the Uses clauses'.

As mentioned, the state of the code is more a prof of concept and does include code that is more a comment and an intent to what I had planned at that point of time - but it has now been laying around since summer, and I will not get this perfected in foreseeable future so it will have a better life set free.

The code can be found here: https://github.com/SteveNew/CodeEditorPaintTextPAL


Saturday, 18 February 2023

IAP Client, therefore IAM

- or creating a simple Google IAP client using JOSE and a service account key file.


Google offers a massive amount of services and APIs to these, and I doubt anyone has the full overview unless they are in that domain naming space 24/7, and the same would be true for Amazon, Microsoft and other offerings.

In this example, I am using Googles IAP (Identity-Aware Proxy) to get an OIDC token that can be used to authorise the requests sent by a service account.

And a disclaimer: This is a conceptual example, for more secure and correct use one should not store any form of keys - so for that look into something like Workforce identity federation - which gives the same short-lived OIDC tokens, with the help of an identity provider. But for the purpose of the example - less is more.

First you would need to create or get the service account key file by using the Google Cloud console to create a new key for the service account, and download and store that in a safe place. The Grijjy guys did a similar example years back, where they used a PEM key based from the P12 file.

I just created a class to load our json key into to extract the values needed, and by using the JOSE library, I did a customer header and claim/payload - which was signed as the example given by the bash shell script in Googles documentation here: Get OpenID Connect Id token from key file.

Since the signing requires RS256, it does disqualify some of the other libraries, but JOSE does support that.

The Google API Client libraries and Cloud Client Libraries tend to use what they call the Application Default Credentials (ADC) strategy, and to mimic that, I added a bit of code that should cover the 3 desktop OSs.

You can read more about ADC here: Google Application Default Credentials

One requirement of the signing is the OpenSSL libraries - JOSE does use these. You could of course also "just" use the EVP_DigestSignXXX functions from the SSLEAY library, and wrap what you needed, but JOSE does such a nice job of that, so why bother.

Adding a scope will give an access_token, whereas without it you will only get the id_token which is the OIDC token.

I did add an expiration check on the OIDC token, and it does seem to do the job of not having to request the token more than needed - but it might not be the perfect way.

The OIDC token is used as a bearer token for the actual requests to the service the proxy works for, so I added some HTTP methods as sample - and they just return an IHTTPResponse interface.

So an example of use would be something like:

uses
  System.Net.HttpClient,
  FbC.IAPClient;

procedure TForm1.Button1Click(Sender: TObject);
const
  cSERVICE_ACCOUNT_KEY='lustrous-stack-342709-93cfcb2a8000.json';
  cIAP_CLIENT_ID='108584532133305403517';
  cURL='https://mytest.com';
var
  IAPClient: TIAPClient;
begin
  IAPClient := TIAPClient.Create(cSERVICE_ACCOUNT_KEY, cIAP_CLIENT_ID, cURL);
  try
    Memo1.Text := IAPClient.IdToken;
//    Memo1.Text := IAPClient.Get('/companies').ContentAsString();
  finally
    IAPClient.Free;
  end;
end;

The IdToken property should not be public, and the client code is just meant as a starting point - since it does solve the painful bit - signing and authentication.

The code for the conceptual IAPClient can be found as a gist here: Delphi Google IAPClient

Requirements are also:

JOSE library: https://github.com/paolo-rossi/delphi-jose-jwt

The appropriate OpenSSL dlls: https://github.com/IndySockets/OpenSSL-Binaries

An implementation of TOAuth2Authenticator with this might have been a good idea, but ...

Well I hope it will at least get you on the right track, if you need to go through an IAP. There is no check for an unsuccessful attempt to get the OIDC token - it will just return an empty string - so that is meant as homework.

/Enjoy

Wednesday, 22 June 2022

A SET up

- or how the for-in statement changed  recently.


Before Delphi 10.4, the statement:

for integer in [] do 

would operate on a set, but since then it now operates on an array. Which then also means a bit of different behaviour.

I had missed this change completely, and only recently gotten aware of it since we had a build issue - mixing source from different IDE versions. (BTW: Do not do that).

Since it previously worked on a set - the "list" when traversed would be an ordered list of values with an ordinal value no bigger than 255, and no more than 256 elements, that is now changed. I will list a few examples - illustrating the pre-10.4 behaviour compared to 10.4 and later.

Duplicates and ordering


var
  i: integer;
begin
  for i in [42, 10, 42, 3, 42, 7] do
    WriteLn(i.ToString);
end.

returns:

10.4+: 42, 10, 42, 3, 42, 7
pre10.4: 3,7,10,42

Range


var
  i: integer;
begin
  for i in [42, 365, MaxInt] do
    WriteLn(i.ToString);
end.

10.4+: 42, 365, MaxInt
pre10.4: Does not compile - In 10.3 you get an E1012 Constant expression violates subrange bounds (earlier you might also get an E2024)

To solve that you could replace it with something like:

uses
  System.Types,
  System.SysUtils;

var
  i: integer;
begin
  for i in TIntegerDynArray.Create(42, 365, MaxInt) do
    WriteLn(i.ToString);
end.

I do think the change is a step up, and does syntax-wise work more like one would expect, so a change for the greater good - but do be aware of the change of behaviour. Another benefit of a newer version is the usage of inline variable declaration and type inference, like in this case:

for var i in [42, 10, 42, 3, 42, 7] do
    WriteLn(i.ToString);

/Enjoy

Thursday, 9 September 2021

My favorite %11 new things in Delphi 11 Alexandria

- or all things "eleven", watch out for dialects.

With the public release of Delphi 11 (and RADStudio and C++Builder) today, I would like to share my %11 initial favorites in the new release.

%01. Styled Form designer

Together with the IDE HighDPI support, it is great that the gap between the running UI and the UI while designing has been reduced, and keeps in my opinion Delphi IDEs the best to design visual applications - whether it is on desktop OSs or mobile OSs.

%10. HTTP/2 support

I am looking forward to start experimenting with this, and see how much benefit and performance it will give when taking advantage of fully.

%11. Remote Desktop Support improvement

In this world where more people are coming to their senses, and wish to work remotely, focus on improving the IDE experience with remote connection is nice. And the things done can also benefit the applications build.


But there are many other things that not even a list of $11 things would cover it, and I am really looking forward to also experience to the various optimizations and running the IDE in HighDPI on my old Surface Pro.

Go EMBT :)

There is one slightly annoying thing that might split the Delphi community - adding to the list of:

- Is Delphi pronounced /del·fai/ or /del·fee/?

- Does "then begin" go on together on the same line?

- FreeAndNil?

and now this to split the community further and create fractions:


https://youtu.be/BOUTfUmI8vs

Well the above was just an excuse for me to include that funny Scottish sketch - no harm done I hope.

BTW: If you wonder about the % prefix - the it is the prefix for binary literals adding in Delphi 11.

/Enjoy


Monday, 15 February 2021

Closing in on Modal Jump Lists

- or getting a WM_SYSCOMMAND to a modal dialog.

An idea that initially seemed clever, has been haunting me a bit lately - I did put a modal dialog into a project before the main Application block (Initialize .. Run). Shame on me.

So the code looks similar to like this:

if (TfrmLaunchSetting.Execute = mrOK) then
begin
  Application.Initialize;
  Application.MainFormOnTaskbar := True;
  Application.Title := 'MyApplication';
  Application.CreateForm(TfrmMain, frmMain);
  Application.Run;
end;

and the TFrmLaunchSetting.Execute is just a class function returning the ModalResult, from its ShowModal.

But here comes the issue at hand - the Close Window in the task bars Jump List sends a WM_SYSCOMMAND that goes to the system menu in the main window - but if a modal form is shown the main window is disabled - and in this case I do not even have a main form yet.

So TApplication.HookMainWindow to the rescue - that would enable me to intercept messages sent to the main form - and act upon these.

So in the FormCreate of my modal dialog I hook the my hook function up like this:

Application.HookMainWindow(AppHookFunc);

And on FormDestroy I do the following:

Application.UnHookMainWindow(AppHookFunc);

The AppHookFunc goes as follows:

function TfrmLaunchSetting.AppHookFunc(var Message: TMessage): Boolean;
begin
  Result := False;
  if Message.Msg = WM_SYSCOMMAND then
  begin
    PostMessage(Handle, WM_CLOSE, 0, 0);
    Result := True;
  end;
end;

This way modal dialogs can react to Windows messages that normally be intended for the main form.

There are probably side-effects - but the issue at hand is solved - for now?

BTW: Yesterday was Delphi 26th birthday - I did not forget - but I am still wrapping up the present. Stay tuned.

/Enjoy

Wednesday, 30 December 2020

It deploys and runs - what a Big Sur prize

- or the initial steps to get a Windows IDE to run cross-platform using CrossVCL.



Sorry about the pun, and I should also mention that this project is WIP, so no workable release/code yet.

Update: In the original image above the language selection was broken/disabled. Read the update in the end of the post on the changes I decided to do to makes this work better overall.

A few days back was a new update of CrossVCL announced in my email - for the lifetime license I had bought years earlier - which triggered an idea.

Saturday, 28 November 2020

A Set back?

- or how could I forget some set operators.


Recently a colleague of mine asked me to review some old code, and a line similar to the one below pop into my view as strange:

if (doorStates * [dsClosed, dsUnlocked] <> []) then

It had been so many years since I had used that specific syntax, that I completely forgot about some of the set operators in Pascal and Delphi - so I thought I would write up a small post on Sets in Pascal/Delphi.

In regards to the silly doorStates example above - here is a little riddle: When is a door not a door?

Saturday, 31 October 2020

Not exactly Kierkegaard - pun intended

- or the books on Delphi keep coming.

Well the pun in the title would probably need a bit of explaining, so the reference is to Søren Kierkegaard (1813-1855) - the Danish philosopher, theologian, poet, social critic and religious author who is widely considered to be the first existentialist philosopher - but his surname is also pronounced as the Danish word for graveyard or churchyard.

I sometimes still hear people say, that nothing is happening in relation to Delphi in general or more specific in the Delphi book area - but that is not true.

It might have been many years since a Danish book on Delphi was published - but there where many in the early days - I had only 2 of the 15-16 published, all the rest I had were in English. So the scene for Danish Delphi books does feel like a "kirkegård".

And it is all my fault - I do prefer my technical books (and my software) in English, and I am sure most Danish developers feel the same.

But when you look at the number of English books that has been published the last couple of years - the technical quality, the passion, level of detail and diversity of topics matches greatly what also has been going on in the rest of the Delphi community - if you haven't noticed you might be looking in the wrong places.

Fellow Embarcadero MVP Patrick Prémartin has started to setup a nice site called delphi-books.com - some books still need to be added at the time of writing this. - no books in the Danish section yet - but covers are scanned. Update: Patrick has uploaded the info and covers I provided him with - and also published an extensive open-data API for the site.

I know Patrick has grouping by "year published" on his to-do list, that will help indicate how much great content has been published in traditional book form the latest years - so a big thanks to all the authors and publishers - for keep doing this non-trivial task of writing books.

It is almost 30 years since I co-authored two books on Paradox DOS - in Danish and just prior to Paradox Windows was launched - they were not bestsellers btw 😁. But I still remember the tolls it took on everyone, and still surprised that my then to-be-my wife, stayed.

/Enjoy some of these great books.

Monday, 31 August 2020

Hygge by the fireside

- or a fireside chat with Jim McKeeth


End April in the evening Jim and I had a fireside chat, which should had been in front of our masonry oven - but I ended up having it from my home office.




You can see the chat here - it is a bit long but I think we had fun, and to help you through it, I have done this post as a commentary track, and put a bit more details in various places.

And the word hygge now seems to have gotten into the Oxford English Dictionary - but still pronounced wrong :)