How to get Login Dialogs Appearing on the TaskBar

May 9th, 2019

Most of the applications I have worked on in Delphi are database apps that may present a splash form quickly followed by a login dialog.  If the user fails to authenticate, the application needs to terminate gracefully.  The only way to do so cleanly is to modify the DPR code with some conditional logic. I’ve seen scenarios where after the main form was created the login dialog was invoked and if authentication failed everything was torn down. This complicates the shutdown logic, and often didn’t work well, encouraging a call to Halt() and sometimes leaving the process in memory.

Any long time Delphi user knows that messing with the generated DPR code in Delphi can cause all sorts of grief later when Delphi tries to auto create forms and add units to the uses clause.  That is out of scope for this post, suffice to say that it is possible to write something like this:

var
  User :TUser;
begin
  Screen.Cursor := crAppStart;
  try
    Application.Initialize;
    Application.MainFormOnTaskbar := True;
    Application.Title := 'My Secure App';
    Application.CreateForm(TMainDm, MainDm);
  finally
    Screen.Cursor := crDefault;
  end;
  User := TfrmLogin.Login
  (
    function (const UserName,Password :string) :TObject
    begin
      Result := MainDm.Session.FindWhere<TUser>(
        Restrictions.&And(
          Restrictions.Eq('UserName',UserName),
          Restrictions.Eq('Password',Password)
        )
      ).FirstOrDefault;
    end,
    {
      UserName can be passed as first parameter so don't
      have to type it in all the time
    }
    ParamStr(1),
    3  {credential retries available }
  ) as TUser;
  if User <> nil then
  begin
    Application.CreateForm(TfrmMain, frmMain);
    frmMain.CurrentUser := User;
    Application.Run;
  end;
end.

The problem is that the Login Dialog does not appear on the Windows Taskbar. If it is hidden behind other windows, the user may think the application has not been launched and attempt to start another instance. There is no easy way for the user to bring the login dialog to the foreground short of closing other windows that may be in front of it. Putting the form on the taskbar solves this. As a quick solution I looked at the SetMainForm method in the Vcl.Forms unit, and decided to extract the ChangeAppWindow() procedure since it is not available outside of the Forms unit. Then I simply called it from this event, and voila! a taskbar button showing the Login form.

procedure TfrmLogin.FormCreate(Sender: TObject);
begin
  ChangeAppWindow(handle,True,True);
end;

I’m sure there are reasons why this method is not exposed as a public TApplication class procedure, but perhaps it could be with a usage caveat.

EF Core - Burning the Database to the Ground

February 1st, 2019

During development, you sometimes want to make database changes that a migration cannot handle.  One such example is changing the datatype of a primary key column from an int to bigint.  In such a case you may want to burn the database to the ground and have a single migration that creates all the database structures defined through the model to date.  Some developers routinely remove all migrations to “cleanup” the code.

The procedure to do so is different for EF vs EF Core, and if you don’t do it the right way, things can get screwed up and be hard to fix.  With EF Core the easiest way I have found to burn the database to the ground is to use the PMC command:

update-database 0

This is a little different than simply removing all the database tables from a SQL utility like SMS.  It actually removes all tables, but ensures that the __EFMigrationsHistory table is present with 0 rows.

Then you can create delete all the files in the Migrations folder of the C# project and create a new initial migration:

add-migration "Some Title"

and generate the new structures:

update-database

Elementary - Sherlock’s OS?

December 20th, 2018

Recently the hard drive in my Toshiba Satellite gave up the ghost, so I decided to stick in an SSD and update the OS.  Originally the laptop shipped with Windows 8 (yeach!).  The laptop kept hanging as it accessed the hard drive.  I tried repairing it by booting off a Windows CD, but it kept locking up.  Even after installing a new SSD this issue persisted.  I could not get any version of Windows to install.

Finally I decided that I would try to install a Linux Distro.  I had previously used Ubuntu and found it to be reasonably reliable and user friendly,  Googling for Distro rankings I came across Elementary OS.  It’s Mac like UI intrigued me, so I set about installing it.  Unlike Windows, the Linux distro installed without issue on my SSD, and seems quite quick.

I happily discovered that Firefox and Skype are available and work quite well although installing them was a little more complicated than running a Windows installer.  Unfortunately I cannot say the same for VMWare Player, so for now running my VMs on the laptop is not possible.  Between the apps that come bundled, and those available for this Ubuntu based Linux distro, I have everything an average use would need on a daily basis.

Unfortunately I installed Loki (v4) and to “upgrade” to the latest OS version of Juno (v5.0) meant a complete re-install of the OS and apps.  Hopefully future “upgrades” will be available using the AppCentre.

The Web vNext

October 25th, 2018

I have been reading a lot about Web development lately, and pondering the future of web development.  For the longest time I shied away from Web development, largely because it was so laborious and frustrating.

I dabbled a bit back when people were using COM objects with VBScript on the server and Javascript on the client in classic ASP pages. Even back then, companies were making software look like Windows applications within the browser (IE).  By today’s standards, those applications look dated, but today’s web SPAs function in a similar manner, although great progress has been made in standardizing browsers, abstracting out their idiosyncrasies using frameworks, and handling variable display sizes.  My current experience is that it’s still harder and more time consuming to develop a good web application, and they are still not as rich as a Windows app IMHO.

That begs the question as to why people are writing applications for the web anyway.  For eCommerce sites, I get it, but for other line of business applications why not throw off the shackles of HTML/CSS and embrace a new UI framework altogether?  Now I know what you’re thinking…..this guy has lost it and wants to re-invent the web which a lot of smart people have worked on for years to make Web 2.0 a reality.  Before you call the white coats, read on…

When a user goes to a web site for any commercial activity they should be ensuring the website has a valid SSL certificate from a trusted authority.  The Internet is a dangerous place these days where web sites may be trying to attack your computer.  We download content from such sites into our sand boxed browser. This is not that much different than downloading a signed application.  We use signed applications all the time now, when using applications on our phones, tablets and desktops from the “app stores”.  The only difference is whether the store owner i.e.: Apple, has reviewed the application testing for malware.  Open source software such as Tortoise Git is often signed as well to ensure users trust that the application they are getting is from the advertised source and is safe to use.  I think it’s safe to say that most people would trust a signed application.

With that premise in hand, why aren’t we all writing signed Desktop apps using REST back ends?  Or if we really want to leverage single source cross platform applications, why not use WASM with a UI framework that allows an application to be written in languages that are typically used for native desktop, and mobile devices such as C#, Delphi, or C++?

The performance of even Javascript is pretty decent.  Many games have been ported to the browser using Javascript transpilers or EmScripten.  WASM allows developers to take this one step closer to the metal (CPU) and skip the run-time parsing and execution of Javascript.  Blazor is a project that does just that, within the confines of HTML/CSS, but also shows the possibility of using WASM with a different presentation framework such as Uno, or Ooui.  Obviously I’m not the only one thinking that a different presentation layer might be overdue in the web space.

One of the advantages of Blazor is to eliminate some of the third party dependencies, making the development stack more reliable, and to use the same technology and tools throughout.  Of course you can learn and use Javascript throughout the entire stack now, or a Javascript transpiler, but without WASM using your development language of choice is not possible.

I would like to see Object Pascal support the entire development stack.  Preferably the same language dialect and core libraries.  Perhaps something similar to Blazor, or maybe FMX targeting the web with WebGL.  All we need is to be able to capture the compiler IR and feed it into the WASM LLVM back end (okay there might be a little more to it than that).  The web is a huge horizontal market that is ripe for disruption and with the right moves, Delphi could grab a chunk of that segment, making the product relevant again.

What do you think is the future of Javascript on the web?  Will it be dethroned at some point by WASM? Is the future of the Web HTML/CSS, a different UI layer, or perhaps a mix depending on the type of web app?  Should I dust off the Delphi .NET compiler to generate MSIL to feed the Mono WASM run-time, or do we need a way to get the current compilers to output LLVM IR?

Maybe it’s just time to call the white coats as pondering all the options can drive you crazy…

Big Cats Rule

October 19th, 2018

Just as a follow up note to my previous post about using my K750 keyboard on a Mac with VMWare Fusion, I mentioned that my Logitech M510 mouse wasn’t tracking all that well.

In fact, sometimes my keyboard would not seem responsive either.  It seemed to be a problem only when using my external USB 3.0 enclosure which houses the SSD I run my Fusion VMs from.  I thought for a while that perhaps I was experiencing some interference between my WiFi and the Logitech Unifying Receiver.  Odd, because I have been using Logitech for a long time at home without issue.  What lead me to believe it might be interference was an experience at work.  When a new WiFi wap was added close to my machine I got similar behaviour from my keyboard and sometimes the Google speakers would cut out while playing music.  When I switched to a Bluetooth keyboard the issue stopped.

As a result, I was looking around for a Bluetooth keyboard and mouse combination that I liked to replace mine.  Unfortunately the only solar keyboard I could find was the Logitech ones I already owned.  Even Logitech for some reason wasn’t making a solar Bluetooth version.  I love never having to charge or replace batteries.  I wish my mouse was solar too!

For kicks, I did some googling to see if other Mac users were having issues, and eventually found links that indicated people had keyboard and mouse issues after upgrading OS/X to High Sierra, which was when my keyboard issues started (although I never connected the dots myself).  One poster had similar problems with a USB device and indicated that for whatever reason, when he plugged the USB device into a hub rather than directly into his Mac mini the problem did not occur.

I dug up a USB hub I bought as part of a tub of miscellaneous cables at a garage sale, plugged my USB SSD and unifying receiver into it and my problems disappeared!

As far as I am concerned the OS/X versions named after the big cats were less problematic.

Windows 10 Updates Suck!

August 27th, 2018

I have no issue with Microsoft wanting to patch the OS and bundled applications to make them more reliable.  The problem I have is that Windows 10 Updates are always being applied at an inconvenient time.  If you defer an update you have limited choices, and more often than not, Windows just re-starts on it’s own to apply them without me even knowing one was pending.  I have a bad habit of keeping scratch notes in a NotePad++ file and not saving it.  More than once Windows has re-started and I’ve lost those notes.

The worst thing is, it can take Windows a long time to apply an update and in the mean time you’re twiddling your thumbs.  What was wrong with the way updates have been handled for the last ~20 years?  Worse yet, some of those Windows Updates have caused issues, and required rollbacks.

We all know software is more complex than ever and hard to get right, so why would Microsoft force updates upon their user base?  At least let the user have the illusion they are in control of their own computer.  Apple notifies of updates for Mac OS/X, but they don’t apply them automatically.

Nothing alienates a user more than being inconvenienced by their OS, and there are lots of free alternatives these days.

Using a K750 Mac Keyboard with VMWare Fusion

August 23rd, 2018

I just created a VM for the Beta test and decided I am going to use it on my Mac for a change. Rather than using a KVM I bought a Logitech M510 mouse, and K750 PC keyboard and bound it to one unifying receiver. Normally I just pull the USB receiver from my PC, put it into my Mac mini, switch the input on my display and I’m off to the races. This is not ideal in that some Mac keyboard mappings are then unavailable to me, but since I mainly run Windows VMs, that was okay until a leg broke on my PC keyboard.

I decided that I would start using my Mac K750, but re-discovered that the function keys are by default mapped to Mac OS/X special functions, and to use the function keys I had to press the fn + F which is a pain because of the location of the fn key and my muscle memory.

I tried using the tips on Malcolm Groves blog but without success as I am running High Sierra. I even installed Karabiner to remap the function keys to normal F keys and that didn’t seem to work for me. What did work was installing the Logitech Control Center. I didn’t have to re-map any keys it just worked…

I of course have VMWare Fusion 10’s Windows 10 Profile Keyboard mapping set to disable Mac OS Host keyboard shortcuts.

Now the only issue I have is that the Logitech M510 mouse does not track very well, and sometimes appears to lose it’s connection to the receiver.  If I lift it up and put it back down, I get my mouse cursor back, but it’s so frustrating I have started using an old Bluetooth Apple Mouse I bought at a garage sale for 25 cents.  Apparently Logitech is known for poor Mac support.

Why I Use(d) Still Use Delphi

July 26th, 2018

I started using Object Pascal (Delphi) because it was VB like without the ugly syntax of VB, and it had the power of C++.   Namely that you could create as well as consume COM objects and it was natively compiled with at the time a very fast compiler when compared to C++.  The VCL was a stable UI framework that was simple to use and flexible enough that unusual use cases were still possible.

Sadly, now I use Delphi less and less and for maintenance work only, or personal and open source projects.  The community has dwindled from what it was once, local jobs are harder to find, and many luminaries have been lost to the evil empire (M$) and it’s technology.

I must admit that I am now working predominantly on C# .NET Core projects. I would gladly come back from the dark side if someone wanted to entice me with a interesting Delphi project. I find C# syntax more terse and unreadable than Object Pascal, but there is no mistaking the power of LINQ, the PPL, and the abundance of open source projects and technical resources. .NET native also makes adoption of C# even more tempting. If they can write Kestrel in C# you should be able to write anything that requires good performance in C#. I would love to see some Delphi web server benchmarks and how they compare to Kestrel. Favorable results might generate more interest in Delphi as would compiler benchmarks.

I love Delphi. I wish it a bright future.  Without new developers it will most certainly fade away over time.  New developers shy away from languages that won’t get them jobs.  An investment in learning a language, an IDE, and run-time libraries simply has to pay off.  Without a growing market share, expensive tools have to provide developers with a competitive edge. For this reason, I applaud EMBT’s release of the Community Edition. I hope it will bring new blood into the development community and spark more open source projects. There are some amazing open source projects out there that could use Community Edition to further their efforts.

There are also many exciting things happening in the land of Pascal that I hope will expand the community. REMObjects has released their Oxygene compiler that can also target WASM as well as native code. Smart Mobile Studio has released version 3 of their Pascal language targeting Javascript, and TMS has introduced a similar product called WebCore based on the FPC Javascript transpiler.  EMBT has hired Jon Aasenden and purchased Sencha so who knows what they have planned. With UniGUI and other frameworks Object Pascal (or rather different dialects) have many more options to target the web than only a couple years ago. I long for the day when I could use the same Object Pascal language for web, desktop, mobile and server development without compromising the results. Is it time for a language standard?

Buying from Amazon - Caveat Emptor

May 8th, 2018

I just bought a pair of BlueDio T4S headphones from Amazon.  I received the package and went to the Bluedio site to verify my purchase for warranty purposes, only to discover that BlueDio is offering the same headphones to consumers for $56.99 ($3 less than Amazon).

I called Amazon to find out why this was the case, and discovered they do not offer a lowest price guarantee like a lot of brick and mortar stores, and claimed they have no control over manufacturers offering their products directly to consumers.

I find it hard to believe that Amazon does not have anti-competition agreements with their vendors, otherwise why would anyone go to Amazon other than to find the product they wished to purchase and then buy it directly from the manufacturer?  The whole capitalistic distribution model would no longer apply, and Amazon as a middleman could be completely cut out.

The moral of the story is, caveat emptor (buyer beware), you may not get the best price from Amazon, so do some research before buying there.

Is this Feature Supported?

January 22nd, 2018


Quite often new features are added into a code stream for demonstration purposes, or need to be hidden because they are not quite ready for release (especially true for monolithic EXEs), or the client cannot upgrade their database structures yet.

There usually are various home grown approaches to accomplish this ranging from command line parameters (beta switches to enable or disable functionality), to one off database metadata queries.  These approaches can be unified in an interface added to your database “data session” as shown in the following code snippets.


type
  TFeatureSupportedPredicate = reference to function(DataSession :IDataSession): Boolean;
  TFeatureInfo = class(TObject)
    Supported :integer;
    FeatureSupportedPredicate :TFeatureSupportedPredicate;
  public
    constructor Create;
  end;

  constructor TFeatureInfo.Create;
  begin
    inherited;
    Supported := -1;  //used to indicate the test for existence has not been performed
  end

type
  TDataSession  = class(TInterfacedObject,IDataSession)
  var
    FFeatureSupportDictionary :TDictionary<string,TFeatureInfo>;
    constructor Create; override;
  end;


  constructor  TDataSession.Create;
  begin
    //do some stuff
    FFeatureSupportDictionary := TDictionary<string,TFeatureInfo>.Create;
  end;

procedure TDataSession.AddFeatureSupportPredicate(
            const FeatureName :string;
            Predicate :TFeatureSupportedPredicate);
var
  FeatureInfo :TFeatureInfo;
begin
  if FFeatureSupportDictionary.ContainsKey(FeatureName) then
    raise EFeatureSupportException.
                      CreateFmt('A Feature Support Predicate is already '+
                                'registered with the Name: ''%s'' ',[FeatureName]);
  FeatureInfo := TFeatureInfo.Create;
  FeatureInfo.FeatureSupportedPredicate := Predicate;
  FFeatureSupportDictionary.Add(FeatureName,FeatureInfo);
end;

function TDataSession.IsFeatureSupported(const FeatureName :string) :boolean;
var
  FeatureInfo :TFeatureInfo;
begin
  Result := False;
  if FFeatureSupportDictionary.TryGetValue(FeatureName,FeatureInfo) then
  begin
    if FeatureInfo.Supported = -1 then
      FeatureInfo.Supported := ifthen(FeatureInfo.FeatureSupportedPredicate(Self),1,0);
    Result := Boolean(FeatureInfo.Supported);
  end;
end;



Now wherever you pass or inject your IDataSession interface, which in a Client/Server application is almost everywhere, you will have access to the FeatureSupport functionality, and you can add/test predicates with the following code snippets:

  AddFeatureSupportPredicate(SomeFeature,
    function(DataSession: IDataSession): Boolean
    begin
      Result := DataSession.TableExists('SomeTableForTheFeature');
    end);

if DataSession.IsFeatureSupported(SomeFeature) then ....