Another itch the OTA couldn’t scratch…

By | March 23, 2017

Overview

So in my last post I said there were a few things to fixed and / or enhance. In this post I’ll explain how I fixed two issues.

The two issues I’ve fixed are stoppping the timer which closes the Message View if a re-compilation occurs (very simple and I should have done this in the first place) and only closing the Message View if the RAD Studio Desktop remains the same as when the timer was started.

The Fixes

Stopping the Timer on Recompilation

This fix couldn’t be simpler and I really should have done this in the first place. To stop the timer on a recompilation I’ve added a call to disable the timer in the Compile Notifier’s ProjectGroupCompilationStarted method as below.

Procedure TMVHCompileNotifier.ProjectGroupCompileStarted(Mode: TOTACompileMode);

Begin
  FTimer.Enabled := False;
End;

Finding the Name of the Active Desktop

The next bug was a little more involved. What was happening before I fixed this is that if you debug an application your RAD Studio Desktop changes (usually) and the Message View in the debugging Desktop was being hidden NOT the one in your main Desktop. The behaviour I wanted is that the main RAD Studio Desktop is hidden but to do that I needed to track which Desktop was active. A search of the Open Tools API files didn’t provide any interfaces I could use so I was back to manipulating the IDE directly as before. After a quick look around the IDE I found what I was lookng for.

In the above image (from my Delphi IDE Explorer) I found a custom combo box in the main application form called cbDesktop which as shown above contained my main RAD Studio Desktop name in the Text property. So my first thoughts on solving this problem were to access the combo box directly. Now you will notice above that the combo box is a TDesktopComboBox, a component we don’t have access to therefore I cannot cast or assign the reference in order to access the Text property. So I thought I would access the selected item using the TCustomComboBox reference and the components Items and ItemIndex properties.

Before I can do that I needed another function in my application to find a component on a form by name. Below is a simple function that takes a form and a name and returns the component reference if the component with the given name is found on the given form.

Function  FindComponent(Form : TForm; strComponentName : String) : TComponent;

Var
  iComponent: Integer;

Begin
  Result := Nil;
  For iComponent := 0 To Form.ComponentCount - 1 Do
    If CompareText(Form.Components[iComponent].Name, strComponentName) = 0 Then
      Begin
        Result := Form.Components[iComponent];
        Break;
      End;
End;

Using the above function I tried the following code to get the current desktop name.

Function  CurrentDesktopName : String;

Var
  F: TForm;
  C: TComponent;
  CB: TCustomComboBox;

Begin
  Result := '(not found)';
  F := FindForm('AppBuilder');
  If Assigned(F) Then
    Begin
      C := FindComponent(F, 'cbDesktop');
      If Assigned(C) And (C Is TCustomComboBox) Then
        Begin
          CB := C As TCustomComboBox;
          Result := CB.Items[CB.ItemIndex];
        End;
    End;
End;

You would think that all is well? Well no. I found during testing (outputting the desktop name to the CodeSite Live Viewer) that in some instances the ItemIndex of the combo box was -1 yet on checking the properties of the desktop dropdown with my Delphi IDE Explorer the Text property was correct. So I needed another solution.

Since I was targetting RAD Studio 2010 and above and my Delphi IDE Explorer had already found the information I needed I though that I would use the new RTTI capabilities in RAD Studio 2010 and above. If you’ve not used RTTI before then I would suggested you create a test project and have a little play as its very powerful and really quite easy to use.

So I redefined my function as below (I’ll walk you thought it below):

Function  CurrentDesktopName : String;

Var
  F: TForm;
  C: TComponent;
  CB: TCustomComboBox;
  Ctx: TRttiContext;
  T: TRttiType;
  P: TRttiProperty;
  V: TValue;

Begin
  Result := '(not found)';
  F := FindForm('AppBuilder');
  If Assigned(F) Then
    Begin
      C := FindComponent(F, 'cbDesktop');
      If Assigned(C) And (C Is TCustomComboBox) Then
        Begin
          CB := C As TCustomComboBox;
          Ctx := TRTTIContext.Create;       // Create context
          Try
            T := Ctx.GetType(CB.ClassType); // Get a type
            P := T.GetProperty('Text');     // Get the Text Property
            If Assigned(P) Then
              Begin
                V := P.GetValue(CB);        // Get the value of the Text property
                Result := V.AsString;       // Return the text value a a string
              End;
          Finally
            Ctx.Free;                       // Free context
          End;
        End;
    End;
End;

The first thing to do if you want to use RTTI is you must create a TRTTIContext in which you can access the RTTI attributes of an object. Next we need to get the type of the object we are referring to with a call to the context’s GetType method which takes the objects class type. Once we have this we can access the object’s fields, methods and properties. In this case we just need a specific property so I call the type’s GetProperty method with the name of the property I want. Now that I have the property reference I can call the property’s GetValue method passing the instance of the object to get the value of the property in a TValue record. All we need to do now is call the value’s AsString method to get the property’s string information and return it from the function. You need to make sure that you free the context you’ve created else you will have a memory leak.

So with the above function in place my compile notifier method ProjectGroupCompileFinished gets an additional line of code to store the name of the RAD Studio Desktop in a field at the time of compilation as follows:

Procedure TMVHCompileNotifier.ProjectGroupCompileFinished(Result: TOTACompileResult);

Begin
  If (Result = crOTASucceeded) And (mvhoEnabled In TMVHOptions.MVHOptions.Options) Then
    Begin
      FTimer.Interval := TMVHOptions.MVHOptions.HideMessageViewDelay;
      FDesktopName := CurrentDesktopName;
      FTimer.Enabled := True;
    End;
End;

Also the timer event changes to ensure the Message View is only closed when the desktop is the same as when the compilation started.

Procedure TMVHCompileNotifier.CloseMessageView(Sender: TObject);

Begin
  If CompareText(FDesktopName, CurrentDesktopName) = 0 Then
    Begin
      FTimer.Enabled := False;
      HideMessageView;
    End;
End;

I hope the above gives people further ideas on how to achieve interesting stuff in the RAD Studio IDE but just remember that you’re mucking about with the actual IDE and the names and locations of element of the IDE might change in different releases so check all the versions of RAD Studio you are going to support.

Downloads

The compiled BPLs and source code for this plug-in can be found on the web page Message View Helper which contains links to a downloadable ZIP file with the BPLs and source code or a GitHub link to the source code.

I had an itch the OTA couldn’t scratch…

By | March 9, 2017

Overview

So there I am, on the train and wondering why the dock areas at the side of RAD Studio can be hidden and auto pop out if you move the mouse over them or use a keyboard shortcut but the bottom dock area doesn’t.

Why was I wondering this… well my day job consumes between 13 to 14 hours of my day and I’ve been getting too tired to do anything once I get back home so I thought I would install RAD Studio on the computer I use on the train which has a much smaller screen than the one at home and do some work while commuting. So I have the screen layed out with Browse and Doc It on the left, visible, things like the Project Manager, Object Inspector hidden on the right and the Message View docked with Find results, Refactoring results, etc at the bottom and I wanted the Message View to go away either by shortcut or automatically after a successful compile.

Can this all be done with the Open Tools API? Errr… not quite!

The Solution

The Open Tools API has the ability to display the Message View if you were to bind it to a keyboard shortcut but unfortunately there is no method of the IOTAMessageServices to do the converse and hide it. To make things harder, I wanted a particular behaviour in that if the Message View is docked in a tab set then I wanted the tab set to hide / show but if docked on its own I wanted just the Message View to hide / show.

You’re probably thinking that this is game, set and match? Well no. Since an Open Tools API plug-in runs inside the IDE then you have access to the internals of the IDE. Now one thing to bare in mind is that the internals of the IDE (I’m limiting myself to the RAD Studio 2010+ Galileo IDEs) are not documented and can be changed between releases by Embarcadero without notice.

So how on earth do you go about fiddling with the internals of the IDE when you know nothing about it? You use something like my Delphi IDE Explorer. I wrote this a VERY long time ago for Delphi 3 and then forgot about it for a long time. Early last year when I came back to coding in general and the Open Tools API more specifically, I decide to update a few things. It was originally sparked by me doing an internet search of my name and / or email address, which I do periodicaly, to see if here are any nasties on the internet like leaked passwords (which I’ve found before!). Anyway I found a link to Thomas Mueller’s website where he had an updated version of my project which he was adding functionality to. Rudy Velthuis has something similar but not based on my code. What this made me do was do my own updates to get it working in Seattle but I also added the new RTTI functionality for RAD Studio 2010+ which gives you a load more information about the IDE than the previous versions. Anyway, it allows me to look around the IDE and see how things are constructed.

By trial and error I found out how the IDE behaviours when docking windows on their own or in tabs or floating, etc. What follows are the fruits of this exploration.

Adding an Action for the Keyboard Shortcut

I decided to add an Action to the IDE for the keyboard shortcut rather than an keyboard binding. A keyboard binding is only available if the editor has focus but I wanted to have the shortcut available whereever I was in the IDE. I decide on the shortcut SHIFT+ALT+M as this (according to GExperts) was not in use by the IDE. I didn’t add a menu or an image to the action as it was not needed. There is a menu item for showing the Message View in the View menu and I initially thought I could find that action and add the shortcut but that wouldn’t work as it only shows the Message View.

So in my main wizard’s constructor I create an action as follows:

Constructor TMVHWizard.Create;

Var
  NService: INTAServices;

Begin
  ...
  FToggleMsgViewAction := Nil;
  If Supports(BorlandIDEServices, INTAServices, NService) Then
    Begin
      FToggleMsgViewAction := TAction.Create(NService.ActionList);
      FToggleMsgViewAction.ActionList := NService.ActionList;
      FToggleMsgViewAction.Name := 'DGHMsgViewHelperToggleMessageView';
      FToggleMsgViewAction.Caption := 'Toggle Message View';
      FToggleMsgViewAction.OnExecute := ToggleMessageViewAction;
      FToggleMsgViewAction.ShortCut := TMVHOptions.MVHOptions.MessageViewShortCut;
      FToggleMsgViewAction.Category := 'OTATemplateMenus';
    End;
  ...
End;

The above technique for adding actions to the IDE with the Open Tools API has been written about in Chapter 15: IDE Main Menus. One thing you MUST do is hold a reference so that your destructor can free the action and be a good citizen of the IDE else you’ll leak memory in the first instance or get errors when loading / unloading the package repeatedly. The destructor is very simple:

Destructor TMVHWizard.Destroy;

Begin
  ...
  If FToggleMsgViewAction <> Nil Then
    FToggleMsgViewAction.Free;
  ...
  Inherited Destroy;
End;

Finally the notifier event that is called by the action is defined as follows:

Procedure TMVHWizard.ToggleMessageViewAction(Sender: TObject);

Begin
  ToggleMessageView;
End;

ToggleMessageView is a funtion that I’ve written and I’ll explain it and it’s associated functions in a while.

Hiding on Successful Compilations

So the next thing I wanted to do was hide the message view on successful compilation. I wanted to only close the view if the compilation was successful and the messages didn’t contain errors or warnings but the Open Tools API doesn’t expose the messages themself so this later criteria cannot be currently done. I do have an idea to resolve this as the Message View is a form of TBaseVirtualTree, one of my faviourite controls however I can’t just get a reference and cast it as this is an IDE specific version. What I need to find is where the unit is defined in the IDE and see if I can add it to my project at design time to allow me access to the treeview.

Anyway, for the successful compilation of a project I decided to use the IOTACompileNotifier which I’ve written about before in Notify me of everything… – Part 1. I only need the ProjectGroupCompileFinished method to know if the project(s) have been compiled successfully. So I defined the following implementation:

Procedure TMVHCompileNotifier.ProjectGroupCompileFinished(Result: TOTACompileResult);

Begin
  If (Result = crOTASucceeded) And (mvhoEnabled In TMVHOptions.MVHOptions.Options) Then
    Begin
      FTimer.Interval := TMVHOptions.MVHOptions.HideMessageViewDelay;
      FTimer.Enabled := True;
    End;
End;

The method checks that the compilation(s) was successful and that the options to automatically close the Message View is enabled, then it sets the timer interval and starts the timer. The timer event handler is as follows:

Procedure TMVHCompileNotifier.CloseMessageView(Sender: TObject);

Begin
  FTimer.Enabled := False;
  HideMessageView;
End;

It disables the timer and calls a method to hide the Message View. Currently no checks are made for changing desktops between timer start and finish or if a second compilation is started before the timer expires but I’ll do something about those at a later date.

“Open Tools API” Functions

I’ve placed all the “interesting” funtions is a unit called MsgViewHelper.OTAFunctions.pas. Although these are not all IOTAXxxxx interface related they to muck about with the IDE so I thought the name still applied.

The following functions all contribute to hiding and showing the Message View however not all are exposed by the unit for calling.

FindForm

This first function has the sole purpose of finding the Message View form in the IDE’s list of forms. When you look into the IDE (and for that matter your own applications) you will find all the created forms in a list of forms in the Screen global variable. This method iterates through them looking for a form with the given name and return’s its reference else if not found returns nil. Although this is a multiple purpose function, in this application is is used only to find the Message View form.

Function FindForm(Const strFormName : String) : TForm;

Var
  iForm: Integer;

Begin
  Result := Nil;
  For iForm := 0 To Screen.FormCount - 1 Do
    If CompareText(strFormName, Screen.Forms[iForm].Name) = 0 Then
      Begin
        Result := Screen.Forms[iForm];
        Break;
      End;
End;

IsDockableClassName

This method checks the given TWinControl’s classname against an array of classnames which are the classname’s of various docksites in the IDE. I check the classname rather than the control name as some of these are created dynamically. I identified the names of the dock site classes by inspecting the IDE structure with my Delphi IDE Explorer.

Function IsDockableClassName(Const P : TWinControl) : Boolean;

Var
  iDockClsName: Integer;

Begin
  Result := False;
  For iDockClsName := Low(strDockClsNames) To High(strDockClsNames) Do
    If CompareText(P.ClassName, strDockClsNames[iDockClsName]) = 0 Then
      Begin
        Result := True;
        Break;
      End;
End;

FindDockSite

This method tries to find the docksite in which the Message View form is docked. It walks backwards through the list of parent controls looking for a control with a classname that matches one of the known docksite classnames. If found the docksite reference is returned. A TWinControl is returned rather than a form because when a form is docked on its own it is placed in a panel not a descendant of a TForm.

Function FindDockSite(Const SourceControl : TWinControl) : TWinControl;

Var
  P : TWinControl;

Begin
  Result := Nil;
  P := SourceControl;
  While Assigned(P) Do
    Begin
      If IsDockableClassName(P) Then
        Begin
          Result := P;
          Break;
        End;
      P := P.Parent;
   End;
End;

IsMessageViewFocused

I tried a number of ways to determine whether the Message View was the focused control or not and ended up using the below. Why did I need this? Well the behaviour I wanted is that not only did I want the shortcut to hide / show the Message View but if the Message View was visible but not focused (in another tab or you are in the editor) then I wanted the focus to change to the Message View and only hide the Message View if it was active.

I settled on this as it was the only reliable way to determine this. It uses the IDE’s main form’s ActiveControl property and check whether its classname is equal to a specific treeview. I checked in previous IDE’s back to 2010 to ensure that this had not changed. When you are doing things like this you cannot assume all IDEs are equal you must check that your assumptions hold true for ALL IDEs you are going to support and obviously it could be broken by a change in the future. If the ActiveControl has the classname expected then the Message View is focused.

Function IsMessageViewFocused : Boolean;

Var
  strActiveControl: String;

Begin
  Result := False;
  If Assigned(Application.MainForm.ActiveControl) Then
    Begin
      strActiveControl := Application.MainForm.ActiveControl.ClassName;
      Result := CompareText(strActiveControl, 'TBetterHintWindowVirtualDrawTree') = 0;
    End;
End;

IsMessageViewVisible

This method is the heart of this application and requires some explanation. Its a little long for my liking but any further refactoring in my mind would prevent someone from understnding it in full. The function returns a set of enumerates that define whether the Message View is visible and whether it has focus. The function needs to cater for floating windows as well has being docked to a tabbed docksite or a panel.

The first thing the function does it find the Message View form. If found we can process, if not we do nothing. Note: we should always find the Message View form.

Next, if the form is floating on its own we can determine the visibility and focusedness (is that a real word???) by calling a few functions of the form. If the form is docked (not floating) then we have a bit more work to do.

Using the form reference we need to find the docksite as what we do here depends upon whether the docksite is a tabbed form or a panel.

If its a panel (docked on its own adjacent to other windows) then we check whether the form is visible and determine its focusedness using the above function. Why did I check the visibility of the form NOT the panel? Well I found that when docked in a panel to hide and show the Message View I needed to hide and show the form rather than the panel as hiding the panel hid the whole docksite rather that the panel and that was not the behaviour I wanted.

If we are docked in a tabbed docksite (which is a form) I determine the visbility of the docksite as a form and the focusedness as before. Hiding and showing the tabbed docksite provide the behaviour I wanted else you would just hide and show the Message View from the tab set.

Function IsMessageViewVisible(Var Form : TForm; Var DockSite : TWinControl) : TMsgViewStates;

Begin
  Result := [];
  Form := FindForm(strMessageViewForm);
  DockSite := Nil;
  If Assigned(Form) Then
    Begin
      If Form.Floating Then
        // If floating
        Begin
          If Form.Visible Then
            Include(Result, mvsVisible);
          If Form.Active Then
            Include(Result, mvsFocused);
        End Else
        // If Docked
        Begin
          DockSite := FindDockSite(Form);
          If DockSite Is TWinControl Then
            Begin
              // If docked to a panel we don't want to hide the panel but the message window.
              If DockSite Is TPanel Then
                Begin
                  If Form.Visible Then
                    Begin
                      Include(Result, mvsVisible);
                      If IsMessageViewFocused Then
                        Include(Result, mvsFocused);
                    End;
                  DockSite := Nil;
                End Else
                // If docked to a tabset we do want to hide the dock tabset
                Begin
                  If DockSite.Visible Then
                    Begin
                      Include(Result, mvsVisible);
                      If IsMessageViewFocused Then
                        Include(Result, mvsFocused);
                    End;
                End;
            End;
        End;
    End;
End;

ShowMessageView

This method shows the Message View. You will note that it uses the Open Tools API to do this but this alone would not focus the Message View if it was already visible in the IDE, so I needed to add focusing the form. However when writing the above function I found that I was calling the same code for showing the form / docksite before each call to this method so I moved those calls into this method.

Procedure ShowMessageView(Form : TForm; DockSite : TWinControl);

Var
  MsgServices: IOTAMessageServices;

Begin
  If Assigned(DockSite) Then
    DockSite.Show
  Else
    Form.Show;
  Form.SetFocus;
  If Supports(BorlandIDEServices, IOTAMessageServices, MsgServices) Then
    MsgServices.ShowMessageView(MsgServices.GetGroup('Build'));
End;

ToggleMessageView

This method, using the information from above regarding form, docksite, visibility and focusedness either hides, shows or focuses the Message View. This method is the one called by the Action installed into the IDE.

Procedure ToggleMessageView;

Var
  Form: TForm;
  DockSite: TWinControl;
  MsgViewStates : TMsgViewStates;

Begin
  MsgViewStates := IsMessageViewVisible(Form, DockSite);
  If Assigned(Form) Then
    If mvsVisible In MsgViewStates Then
      Begin
        If mvsFocused In MsgViewStates Then
          Begin
            If Assigned(DockSite) Then
              DockSite.Hide
            Else
              Form.Hide;
          End Else
            ShowMessageView(Form, DockSite);
      End Else
        ShowMessageView(Form, DockSite);
End;

HideMessageView

Finally this is the method called by the compile notifier timer and it simply hides the Message View depending upon whether its docked or floating.

Procedure HideMessageView;

Var
  MsgViewState: TMsgViewStates;
  Form : TForm;
  DockSite: TWinControl;

Begin
  MsgViewState := IsMessageViewVisible(Form, DockSite);
  If Assigned(Form) Then
    If Assigned(DockSite) Then
      DockSite.Hide
    Else
      Form.Hide;
End;

I don’t know whether this plug-in will be useful to others as it might just be a pecularity of the way I work but I hope that it provides people who are looking into the Open Tools API with ideas when they find that the API does not do all they want.

Downloads

The compiled BPLs and source code for this plug-in can be found on the web page Message View Helper which contains links to a downloadable ZIP file with the BPLs and source code or a GitHub link to the source code.

The Trials and Tribulations of RegEx’ing and Other Stories…

By | March 4, 2017

RegEx’ing C++

So I thought I was on to something using expandable macros to create complex regular expressions. I managed to defined an expression that recognised C++ class definitions and match these throughout all my C++ code (I still had to write all the DUnit tests).

So what am I talking about. In a previous post (C++ Books and Possible Insanity (RegEx’ing C++)…) I thought of an alternate approach to creating regular expressions using expandable macros so that the regular expression definitions looked similar to the Backus-Naur grammar for the thing you’re parsing. So for instance we could define a macro as follows for a C++ identifier:

$(Identifier)=[a-zA-Z_]\w*

This matches any letter or underscore for the start of the identifier and then any letter, number or underscore for the remaining characters. I can then use this macro in another definition as follows for a Nested Name Specifier:

$(!NestedNameSpecifier)=($(Identifier)\s*::)

These can then be used in further expressions as follows:

$(!TemplateName)=$(Identifier)
$(!TemplateNameList)=($(NestedNameSpecifier))?$(Identifier)
$(!SimpleTemplateID)=$(TemplateName)\<($(TemplateNameList))?\>

So with this and a successful matching of class definitions off I when… and eventually came to a halt! Why? The expressions that were being produced for function definitions became way to complex and the regular expression parser (TRegEx in this case) started raising errors because the expressions had exceeded circa 32,000 characters. The reason for this is that the C++ grammar (I was using the C++14 standard as a reference – couldn’t find 11) is very complex and allows the definitions of things like enumerates and classes in-line within a function. I tried to get around this by limiting the expressions to not allow this but I still ran out of characters 🙁

So is this the end of the great experiment? Yes and No! I still think the technique will be useful in the further for me or someone else and for this reason I’ve published the testing application DGH Regular Expressions so that people can use the code I’ve done if it provides useful for them (a simpler grammar like Object Pascal could still possibly be parsed using this technique). The application has a class TDGHRegExPreProcessingEng = Class(TInterfacedObject, IDGHRegExPreProcessingEng) in the module DGHRegEx.RegExPreProcessingEng.pas which is a pre-processor for your macro definitions.

Does this mean that the OTA project to provide code completion and browsing using CTRL+SHIFT+UP/DOWN for C++ Builder is dead? No. All the above means is that I need to write a recursive descent parser. Is this going to be in C++… err… no! Why? I need a C++ parser for my Browse and Doc It plug-in so I will create one in Object Pascal that just does declarations and reuse that code. I’ve already started compiling a Backus-Naur grammar file for C++14 (I don’t find the way the grammar is described in the standard very readable) and I’ve already started to refactor the code that makes up Browse and Doc It.

Open Tools API Code

I’ve also made a decision to curtail my backwards comparability for OTA code to RAD Studio 2010 and onwards. Why? Well going any further back preclude the use of things like namespaces, generics, anonymous methods, regular expressions, to name a few.

Last night I was making a new OTA tool (which I’ll write about separately) backwardly compatible to 2010 and even going back that far causes issues with the resolution of namespaces in 2010 and XE (makes the uses causes messy).

C++ Books and Possible Insanity (RegEx’ing C++)…

By | January 18, 2017

C++ Books

So a number of weeks ago I asked a question on G+ about peoples preferences for buying technical books (hard copy, soft copy or both). The reasons I asked was that I wanted to buy a number of books to re-learn C++. I originally (tried) to learn C++ back around 2000 and I can't say I did a very god job. I think I understood most of the language features but didn't know the run-time library at all. I have released a few bits of C++ code recently and one observation that was made was that I programmed C++ Builder in a Delphi way not a C++ way. That was a valid observation and it was as I mentioned above, due to me not knowing the C++ run-time and Standard Template Library.

So below is a list of the books I ended up buying as I think they could be useful to others – some who may be interested in learning C++ and are from a Delphi background or others who may find them generally useful.

Programming: Principles and Practice Using C++ – Bjarne Stroustrup

As mentioned above I wanted to re-learn C++ from the beginning and after downloading a sample of this book on Kindle I ended up buying the full kindle version and then a number of weeks later a paper back version.

https://www.amazon.co.uk/gp/product/0321992784/ref=oh_aui_detailpage_o02_s00?ie=UTF8&psc=1

The book is essentially a college / university level course book for learning C++ from the very man who invented the language – that was one of the appealing items about the book. Secondly it teachs you C++ in a more modern C++11 way rather than the old C++98 way. One of the aspects of C++ I always struggled with was parameter passing and pointers. I've used Delphi since version 1 in 95 and basically forgotten all I knew about pointer from Turbo Pascal as I've rarely needed to use them.

I found this book pretty good to learn from. I didn't do all the exercises as I was trying to learn as must as I could as quickly as I could however one of the nice aspects of the book is that it starts early on by getting you to create a class which essentially mirrors the STL's vector class which is one of the most useful collections in the STL.

The book has the following chapters:

  • Part 1: The Basics
    • Hello World
    • Objects, Types and Values
    • Computation
    • Errors
    • Writing a Program
    • Completing a Program
    • Technicalities: Funtions, etc.
    • Technicalities: Classes, etc.
  • Part 2: Input and Output
    • Input and Output Streams
    • Customizing Input an Output
    • A Display Model
    • Graphics Classes
    • Graphics Class Design
    • Graphing Functions and Data
    • Graphical User Interfaces
  • Part 3: Data and Algorithms
    • Vector and Free Store
    • Vectors and Arrays
    • Vector, Templates and Exceptions
    • Containers and Iterators
    • Algorithms and Maps
  • Part 4: Broadening the view
    • Ideals and History
    • Text Mnaipulation
    • Numerics
    • Embbedded Systems Programming
    • Testing
    • The C Programming Language
  • Part V: Appendices
    • Language Summary
    • Standard Library Summary
    • Getting Started with Visual Studio
    • Installing FLTK
    • GUI Implementation

One thing it is not is a reference book for the STL, you need another book for that (see below). One criticism of the book I have is that for the code examples it does not use a fixed width font (same for the e-book and paper version). I didn't think this help me understand some of the code example however saying that I don't regret buying the book and will keep referring to it and possible retired my older C++ reference book.

The C++ Standard Library: A Tutorial and Reference – Nicolai M. Josuttis

I have to say from the start that this is a MUST BUY BOOK! It doesn't matter whether you're a beginner, intermediate or advanced C++ programmer I think this book should be on your shelf (virtual or otherwise) as its been in valuable to me learning the STL, C++ String and RegEx.

https://www.amazon.co.uk/gp/product/0321623215/ref=oh_aui_detailpage_o02_s00?ie=UTF8&psc=1

It's a very good reference book which complements the above learning book but it's not just a terse list of interface methods but has tutorials on how to use the various classes. It also has some early chapters that go though C++11 basics, one useful one for me was the use of std::unique_ptr<>.

The book has the following chapters:

  • Chapter 1: About this book
  • Chapter 2: Intoduction to C++ and the Standard Library
  • Chapter 3: New Language Features
  • Chapter 4: General Concepts
  • Chapter 5: Utilities
  • Chapter 6: The Standard Template Library
  • Chapter 7: STL Containers
  • Chapter 8: STL Container Members in Detail
  • Chapter 9: STL Iterators
  • Chapter 10: STL Function Objects and Using Lambdas
  • Chapter 11: STL Algorithms
  • Chapter 12: Special Containers
  • Chapter 13: Strings
  • Chapter 14: Regular Expresions
  • Chapter 15: Input/Output Using Stream Classes
  • Chapter 16: Internationalization
  • Chapter 17: Numerics
  • Chapter 18: Concurrency
  • Chapter 19: Allocators

I thought this book so good I brought it twice (hardback and soft copy).

Mastering Regular Expressions: Understand Your Data and Be More Productive – Jeffrey E. F. Friedl

Hold on I here you say, This isn't a C++ book!. Well yes you're right but I need to first to explain my current madness.

The current project I'm working on is a C++ Open Tools API project to provide C++ Builder with code browsing using the CTRL+SHIFT+UP/DOWN keyboard configuration and Code Completion. It sounds simple BUT is not. The OTA Project itself is IDE agnostic (I'll write about that when its finished) but the hard part is parsing the C++ language. I currently don't have a C++ parser in Browse and Doc It to use (but I do need one) however I thought that would be too much work to get up and running so I chose to try and do it with RegEx instead (see the later part of this article).

https://www.amazon.co.uk/gp/product/B007I8S1X0/ref=oh_aui_d_detailpage_o01_?ie=UTF8&psc=1

From all accounts, even though this book is a little old, it is still THE regular expression book to read. It doesn't use Delphi or C++ but more Perl with a few other languages interdispersed however the languages are immaterial as it does an excellent job of building your knowledge of regular expressions. The book has given me detail behind numerous regular expression elements which tutorials on the net or other net references have not provided. I think that if you want to learn regular expressions (and I strongly suggest everyone does as they may completely change the way you manipulate information) then you can't go wrong with this book.

The book has the following chapters:

  • 1. Introduction to Regular Expressions
  • 2. Extended Introduction Examples
  • 3. Overview of Regular Expression Features and Flavors
  • 4. The Mechanics of Expression Processing
  • 5. Practial RegEx Techniques
  • 6. Crafting an Efficient Expression
  • 7. Perl
  • 8. Java
  • 9. .NET
  • 10. PHP

This book was only available (at sensible prices) in Kindle format.

Effective Modern C++: 42 Specific Ways to Improve Your Use of C++11 and C++14 – Scott Meyers

This was actually the first book I brought (was only available in paper back) however I quickly realised that I didn't understand very much.

https://www.amazon.co.uk/gp/product/1491903996/ref=oh_aui_detailpage_o05_s00?ie=UTF8&psc=1

You need to be reasonable proficient in C++, especially the C++11 language for this book to be relevant. I've currently read very little of the book however it does go into a lot of detail on specific topics. I think it will be useful in the long term but for now I'll be using the other C++ books to get my project complete.

The book has the following chapters:

  • 1. Deducing Types
  • 2. auto
  • 3. Moving to Modern C++
  • 4. Smart Pointers
  • 5. Rvalue References, Move Semantics, and Perfect Forwarding
  • 6. Lambda Expressions
  • 7. The Concurrency API
  • 8. Tweaks

Possible Insanity (RegEx'ing C++)

So have I gone insane? Probably. As I mentioned above I've chosen to use regular expressions to parse the C++ code to help identifier the classes and functons. I've already done the work on the OTA framework for the code and created an initial collaboration object for holding the code structure (all in C++11) but I still needed to define the RegEx code.

Regular expressions as they are currently defined are very powerful however to create a regular expression of the length required to parse elements of code is somewhat impractical so I decided to modify the concept by providing a mechanism to insert macros into the regular expressions.

The screen shot below is an application (sorry in Delphi) I've created to help me generate, test and debug the regular expressions. the file format I've chosen is a little like an INI file. Lines can be commented out with commas at the start. All regular expressions must be defined as a key=value pair and a macro must be defined before it can be used in a regular expression below. The form of the macro should be familiar $(MacroName). The application searches multiple files for an expression and display a treeview of the match results so that I can examine the matches.

What this allows me to do is essentially define the grammar elements of the C++ code as macros and build more complex macros (say for a class header definition) from simpler grammatical elements.

Eventually on Sunday morning I got the full expression for a class header definition to work which means I can proceed with implementing this technique. To help me do this I also spent time creating a SynEdit highlighter for regular expressions (with my modifications) so that I could see into the expression (the full expanded expression can be shown in the editor at the bottom right of the application).

So all I need to do now is write the function expressions, code this all up in C++ (along with unit testing of the macros to ensure the C++ regex is the same as the TRegEx class in Delphi. Then its reading the information, placing it into the structure and providing mechanisms for finding functions.

I shall now go back to my nice padded cell with crayons 🙂

Expert Manager 1.1 (BugFix)

By | January 7, 2017

I’ve just updated my Expert Manager for RAD Studio with a few bug fixes and a little additional functionality. You can now see installation with no Experts node and you can enabled and disable experts via a check box.

A view of the Expert Manager displaying duplicate experts and experts with duplicate paths

There is a current a known issue where the tool does not display any installations on a Window 10 machine with a non-English set-up. If anyone else has experience this I would like to know.

You can get the executable and source code from the page: Multi-IDE Expert Manager

IDE Notifications 1.0a (BugFix)

By | January 6, 2017

I’ve updated the IDE Notifications plug-in to fix an access violation found while compiling 64-bit application.

In order to prevent this from happening again I’ve wrapped all the object calls in methods to intercept nil references.

You can get the updated code from either of the following locations:

OTA Interface Search 1.1a (BugFix)

By | January 6, 2017

Just a quick post to let you all know that I found a bug in the OTA Interface Search utility that prevented it from finding all the interfaces.

This is now fixed and can be download from the following locations:

DUnit Testing in C++ Builder

By | December 30, 2016

Overview

So while building a new OTA project to provide C++ Builder with Ctrl+Shift+Up/Down code navigation and code completion functionality I needed to write some C++ DUnit tests. Now I know that DUnit is no longer being developed and that I should use DUnitX but since I know the framework and am already learning C++ 11 and OTA in C++ builder I didn't want to add another thing to learn at this time however I will sometime in the future.

So why am I writing about this? Well the documentation I found on http://docwiki.embarcadero.com/RADStudio/Seattle/en/DUnit_Overview doesn't work in Berlin and I suspect that it hasn't worked for C++ Builder since the introduction of the new RTTI. It compiles BUT it throws an RTTI exception when run.

So why don't I use the DUnit wizards from the IDE? Well the project one works but the test case version raises an blank exception. I've raised this as a bug (https://quality.embarcadero.com/browse/RSP-16631). Please vote for this if you want it fixed.

DUnit Project

So the DUnit Project wizard in the IDE will create a DUnit project for you as shown below.

//---------------------------------------------------------------------------
// DUnit Project File.
//   Entry point of C++ project using DUnit framework.
//---------------------------------------------------------------------------

#include <System.hpp>
#pragma hdrstop
#include <tchar.h>
#include <vcl.h>
#include <GUITestRunner.hpp>

#ifdef ENABLE_CODESITE
#pragma comment(lib,"CodeSiteLoggingPkg.lib")
#pragma link "CodeSiteLogging"
#endif

int WINAPI _tWinMain(HINSTANCE, HINSTANCE, LPTSTR, int)
{
  try
  {
 Application->Initialize();
 Guitestrunner::RunRegisteredTests();
  }
  catch (Exception &exception)
  {
 Application->ShowException(&exception);
  }
  catch (...)
  {
 try
 {
   throw Exception("");
 }
 catch (Exception &exception)
 {
   Application->ShowException(&exception);
 }
  }
  return 0;
}

The only other things I've added are some compiler conditionals to include CodeSite so that I could put messages in the constructors and destructors of my collaboration object to ensure they were being fired correctly.

DUnit TestCase

Below is a test case similar to that found on the docwiki above.

Declaration

To solve the problem with the RTTI exception I had to add __declspec(delphirtti) to the class declaration. Once this was added the tests ran however there are some peculiarities. It runs tests in the public and published scopes not just published.

The other mistake I made which took a few hours for the penny to drop was I had spelt Setup wrong. It should be spelt SetUp.

#ifndef CPPBuilderToolsParserTestH
#define CPPBuilderToolsParserTestH

#include "CBTBaseTestCase.h"
#include <TestFramework.hpp>
#include "CPPBuilderToolsParser.h"

class __declspec(delphirtti) TCBTParserTests : public TCBTBaseTestCase {
  private:
    std::unique_ptr<TStringList> FCode;
  protected:
    void __fastcall SetUp();
    void __fastcall TearDown();
  public:
    virtual __fastcall TCBTParserTests(String strName) : TCBTBaseTestCase(strName) {};
  __published:
    void __fastcall TestParser();
};

#endif

Implementation

Below is the implementation of the above class which should be straight forward.

#pragma hdrstop
#include "CPPBuilderToolsParserTest.h"
#include "CPPBuilderToolsFunctions.h"
#pragma package(smart_init)

void __fastcall TCBTParserTests::SetUp() {
  OutputCodeSiteMsg("Setup");
  FCode = std::unique_ptr<TStringList>{ new TStringList() };
  String strFileName = ExtractFilePath(ParamStr(0)) + "..\\..\\TestFile.cpp";
  FCode->LoadFromFile(strFileName);
}

void __fastcall TCBTParserTests::TearDown() {
  OutputCodeSiteMsg("TearDown");
}

void __fastcall TCBTParserTests::TestParser() {
  std::unique_ptr<ICBTParser> P { new TCBTParser(L"MyUnit.cpp") };
  ICBTUnit* U = P->Parse(FCode.get());
  CheckEquals(1, U->ClassCount);
}

static void registerTests()
{
  _di_ITestSuite iSuite;
  TTestSuite* testSuite = new TTestSuite("CBT Parser Tests");
  if (testSuite->GetInterface(iSuite)) {
    testSuite->AddTests(__classid(TCBTParserTests));
    Testframework::RegisterTest(iSuite);
  } else {
    delete testSuite;
  }
}
#pragma startup registerTests 33

The only other difference that is noticable is with the static funtion declared at the end to register the test case suites. This and the following #pragma code are there to workaround C++ not having the Object Pascal equivalent to an initialization section.

After Thoughts

I've written this blog post mostly to remind me later on how I solved the issues but hopefullly it will be useful to others wanting to use DUnit in C++ Builder.

Dave.

OTA Interface Search 1.1 and GitHub

By | December 17, 2016

I’ve just update the Open Tools API Interface Search application to provide the ability to target searches based on a secondary search criteria.

You can get more information on the application along with the executable and source code here.

I’ve also started to load my Open Tools API related projects on to GitHub (https://github.com/DGH2112/).

I’ll be loading the following projects over the next few weeks now that I’ve worked out the GitHub Desktop application work flow along with any new ones as I go along:

Note: Browse and Doc It will NOT be one of these.

regard

Dave.

OTA Interface Search

By | December 11, 2016

I’ve just published a new page with an application to help people search to Open Tools API interfaces, method and properties and to provide some help in writing code to get to those interfaces, method or properties by providing a treeview of possible paths to the intended item.

You can get more information on the application along with the executable and source code here.

Hope it helps.

regard
Dave.

EDIT 12/Dec/2016: You need VirtualTreeView and SynEdit components to compile the project yourself.