Sunday, December 28, 2014

How to Display Menu Item Hints in Delphi Applications (Revisited)

Last week I decided I wanted the main menu hints and popup menu hints to display in a tooltip window just like the hints for all the other controls. I figured it shouldn't be that difficult, right. Microsoft does it all over the place so why shouldn't my applications.

Wow did I under estimate what it takes to pull this one off.

It turns out that menuitem hints by design are intended to display in the status bar. Who's bright idea was that? I don't know about you but when I mouseover stuff my eyes look where the mouse cursor is. I hardly ever look down at the status bar.

So, I turned to google and began my search for code. I figured that someone has already done this and I can just implement their solution. Almost but not quite.

Here are my requirements:
  1. Display all main menu hints in a tooltip
  2. Display all popup menu hints in a tooltip
  3. Display multi-line menu hints as multi-lines
I'd like to thank Zarko Gajic and mghie (from stackoverflow) for doing all the hard work and providing the code base that I tweaked in my final implementation.

How to Display Menu Item Hints in Delphi Applications - Zarko Gajic
Display a ToolTip hint on a disabled menu item of a popup menu - mghie

I have heavily commented the code below for a very specific reason. I wanted it to standout from all the other code in my application. Here is what the folded code looks like in my IDE

Yes those are real box drawing characters. I like the way the structured comments keeps all the code needed for the menuhints implementation in a nice, visual group.

Semper Fi,
Gunny Mike

Add to Uses
  Vcl.Menus
  Vcl.ExtCtrls

Interface Section
{┌────────────────────────────────────────────────────────────┐}
{│ MenuHints Type Declaration                                 │}
{├────────────────────────────────────────────────────────────┤}
{│ How to Display Menu Item Hints in Delphi Applications      │}
{│ http://delphi.about.com/od/vclusing/a/menuitemhints.htm    │}
{│ Zarko Gajic                                                │}
{├────────────────────────────────────────────────────────────┘}
{│} type
{│}   TMenuItemHint = class(THintWindow)
{│}     private
{│}       activeMenuItem : TMenuItem;
{│}       showTimer : TTimer;
{│}       hideTimer : TTimer;
{│}       procedure HideTime(Sender : TObject) ;
{│}       procedure ShowTime(Sender : TObject) ;
{│}     public
{│}       constructor Create(AOwner : TComponent) ; override;
{│}       destructor Destroy; override;
{│}       procedure DoActivateHint(menuItem : TMenuItem) ;
{│}    end;
{│} {  End TMenuItemHint }
{└─────────────────────────────────────────────────────────────}


TForm Private Declarations
    { Private declarations }
    {┌────────────────────────────────────────────────────────────┐}
    {│ MenuHints Form Private Declartions                         │}
    {├────────────────────────────────────────────────────────────┤}
    {│ Adapted from Zarko Gajic's article called                  │}
    {│ How to Display Menu Item Hints in Delphi Applications      │}
    {│ http://delphi.about.com/od/vclusing/a/menuitemhints.htm    │}
    {│                                                            │}
    {│ Further adapted by mghie's stackoverflow answer to         │}
    {│ Display a ToolTip hint on a disabled menu item of a        │}
    {│ popup menu                                                 │}
    {│ http://stackoverflow.com/questions/470696/#471065          │}
    {│                                                            │}
    {│ Important:                                                 │}
    {│ Add call to MenuHintOnCreate in the form OnCreate method   │}
    {│ Add call to MenuHintOnDestroy in the form OnDestroy method │}
    {├────────────────────────────────────────────────────────────┘}
    {│} miHint : TMenuItemHint;
    {│} fOldWndProc: TFarProc;
    {└─────────────────────────────────────────────────────────────}
    {┌────────────────────────────────────────────────────────────┐}
    {│ MenuHints Form Private Declartions Contiinued              │}
    {├────────────────────────────────────────────────────────────┘}
    {│} Procedure MenuHintOnCreate;
    {│} Procedure MenuHintOnDestroy;
    {│} procedure WMMenuSelect(var Msg: TWMMenuSelect); message WM_MENUSELECT;
    {│} procedure PopupListWndProc(var AMsg: TMessage);  public
    {└─────────────────────────────────────────────────────────────}


Form OnCreate / OnDestroy
procedure TfrmMain.FormCreate(Sender: TObject);
begin
  {┌────────────────────────────────────────────────────────────┐}
  {│ MenuHints:                                                 │}
  {├────────────────────────────────────────────────────────────┘}
  {│} MenuHintOnCreate;
  {└─────────────────────────────────────────────────────────────}
end;

procedure TfrmMain.FormDestroy(Sender: TObject);
begin
  {┌────────────────────────────────────────────────────────────┐}
  {│ MenuHints:                                                 │}
  {├────────────────────────────────────────────────────────────┘}
  {│} MenuHintOnDestroy;
  {└─────────────────────────────────────────────────────────────}
end;


Implementation Section
{┌────────────────────────────────────────────────────────────┐}
{│ MenuHints Implementation                                   │}
{├────────────────────────────────────────────────────────────┤}
{│ Adapted from Zarko Gajic's article called                  │}
{│ How to Display Menu Item Hints in Delphi Applications      │}
{│ http://delphi.about.com/od/vclusing/a/menuitemhints.htm    │}
{│                                                            │}
{│ Further adapted by mghie's stackoverflow answer to         │}
{│ Display a ToolTip hint on a disabled menu item of a        │}
{│ popup menu                                                 │}
{│ http://stackoverflow.com/questions/470696/#471065          │}
{│                                                            │}
{│ Modified to accomodate multi line hints                    │}
{├────────────────────────────────────────────────────────────┤}
{│ Generic Section                                            │}
{├────────────────────────────────────────────────────────────┘}
{│} procedure TMenuItemHint.HideTime(Sender: TObject);
{│} begin
{│}    //hide (destroy) hint window
{│}    self.ReleaseHandle;
{│}    hideTimer.OnTimer := nil;
{│} end;
{├────────────────────────────────────────────────────────────┐}
{│ procedure: TMenuItemHint.ShowTime                          │}
{│ Modified:  12/27/2014                                      │}
{│ By:        Michael Riley                                   │}
{│ Reason:    Accomodate multi line hints                     │}
{│            Changed the position and size of the TRect      │}
{├────────────────────────────────────────────────────────────┘}
{│} procedure TMenuItemHint.ShowTime(Sender: TObject);
{│}
{│}   procedure Split(Delim: Char; Str: string; Lst: TStrings) ;
{│}   begin
{│}      Lst.Clear;
{│}      Lst.StrictDelimiter := True;
{│}      Lst.Delimiter     := Delim;
{│}      Lst.DelimitedText := Str;
{│}   end;
{│}
{│} var
{│}   r : TRect;
{│}   wdth : integer;
{│}   list : TStringList;
{│}   s,str  : string;
{│}   j,h,w : integer;
{│}
{│} begin
{│}   if activeMenuItem <> nil then
{│}   begin
{│}      str := activeMenuItem.Hint;
{│}      str := StringReplace(str,#13#10,'|',[rfReplaceAll]);
{│}      str := StringReplace(str,#13,'|',[rfReplaceAll]);
{│}      str := StringReplace(str,#10,'|',[rfReplaceAll]);
{│}      while AnsiPos('||',str) > 0 do
{│}      begin
{│}        str := StringReplace(str,'||','|',[]);
{│}      end;
{│}
{│}      list := TStringList.Create;
{│}      split('|',str,list);
{│}      s := '';
{│}      h := Canvas.TextHeight(str) * (list.Count);
{│}      w := 0;
{│}      for j := 0 to list.Count -1 do
{│}      begin
{│}        if j > 0 then s := s + #13#10;
{│}        s := s + list[j];
{│}        wdth := Canvas.TextWidth(list[j]);
{│}        if wdth > w then w := wdth;
{│}      end;
{│}      list.Free;
{│}
{│}     //position and resize
{│}     r.Left := Mouse.CursorPos.X;
{│}     r.Top := Mouse.CursorPos.Y + 20;
{│}     r.Right := r.Left + w + 8;
{│}     r.Bottom := r.Top + h + 2;//6;
{│}     ActivateHint(r,s);
{│}   end;
{│}
{│}   showTimer.OnTimer := nil;
{│} end; (*ShowTime*)
{├─────────────────────────────────────────────────────────────}
{│} constructor TMenuItemHint.Create(AOwner: TComponent);
{│} begin
{│}   inherited;
{│}   showTimer := TTimer.Create(self) ;
{│}   showTimer.Interval := Application.HintPause;
{│}
{│}   hideTimer := TTimer.Create(self) ;
{│}   hideTimer.Interval := Application.HintHidePause;
{│} end;
{├─────────────────────────────────────────────────────────────}
{│} destructor TMenuItemHint.Destroy;
{│} begin
{│}   hideTimer.OnTimer := nil;
{│}   showTimer.OnTimer := nil;
{│}   self.ReleaseHandle;
{│}   inherited;
{│} end;
{├─────────────────────────────────────────────────────────────}
{│} procedure TMenuItemHint.DoActivateHint(menuItem: TMenuItem);
{│} begin
{│}   //force remove of the "old" hint window
{│}   hideTime(self) ;
{│}
{│}   if (menuItem = nil) or (menuItem.Hint = '') then
{│}   begin
{│}     activeMenuItem := nil;
{│}     Exit;
{│}   end;
{│}
{│}   activeMenuItem := menuItem;
{│}
{│}   showTimer.OnTimer := ShowTime;
{│}   hideTimer.OnTimer := HideTime;
{│} end;
{├────────────────────────────────────────────────────────────┐}
{│ Form Specific Section                                      │}
{├────────────────────────────────────────────────────────────┘}
{│} procedure TfrmMain.MenuHintOnCreate;
{│} var
{│}   NewWndProc: TFarProc;
{│} begin
{│}   miHint := TMenuItemHint.Create(self);
{│}   NewWndProc := MakeObjectInstance(PopupListWndProc);
{│}   fOldWndProc := TFarProc(SetWindowLong(VCL.Menus.PopupList.Window, GWL_WNDPROC, integer(NewWndProc)));
{│} end;
{├─────────────────────────────────────────────────────────────}
{│} procedure TfrmMain.MenuHintOnDestroy;
{│} var
{│}   NewWndProc: TFarProc;
{│} begin
{│}   NewWndProc := TFarProc(SetWindowLong(VCL.Menus.PopupList.Window, GWL_WNDPROC, integer(fOldWndProc)));
{│}   FreeObjectInstance(NewWndProc);
{│} end;
{├─────────────────────────────────────────────────────────────}
{│} procedure TfrmMain.WMMenuSelect(var Msg: TWMMenuSelect);
{│} var
{│}   menuItem : TMenuItem;
{│}   hSubMenu : HMENU;
{│} begin
{│}   inherited; // from TCustomForm
{│}
{│}   menuItem := nil;
{│}   if (Msg.MenuFlag <> $FFFF) or (Msg.IDItem <> 0) then
{│}   begin
{│}     if Msg.MenuFlag and MF_POPUP = MF_POPUP then
{│}     begin
{│}       hSubMenu := GetSubMenu(Msg.Menu, Msg.IDItem);
{│}       menuItem := Self.Menu.FindItem(hSubMenu, fkHandle);
{│}     end
{│}     else
{│}     begin
{│}       menuItem := Self.Menu.FindItem(Msg.IDItem, fkCommand);
{│}     end;
{│}   end;
{│}
{│}   miHint.DoActivateHint(menuItem);
{│} end; (*WMMenuSelect*)
{├─────────────────────────────────────────────────────────────}
{│} procedure TfrmMain.PopupListWndProc(var AMsg: TMessage);
{│}
{│}   function FindItemForCommand(APopupMenu: TPopupMenu; const AMenuMsg: TWMMenuSelect): TMenuItem;
{│}   var
{│}     SubMenu: HMENU;
{│}   begin
{│}     Assert(APopupMenu <> nil);
{│}     // menuitem
{│}     Result := APopupMenu.FindItem(AMenuMsg.IDItem, fkCommand);
{│}     if Result = nil then begin
{│}       // submenu
{│}       SubMenu := GetSubMenu(AMenuMsg.Menu, AMenuMsg.IDItem);
{│}       if SubMenu <> 0 then
{│}         Result := APopupMenu.FindItem(SubMenu, fkHandle);
{│}     end;
{│}   end;
{│}
{│} var
{│}   Msg: TWMMenuSelect;
{│}   menuItem: TMenuItem;
{│}   MenuIndex: integer;
{│}
{│} begin
{│}   AMsg.Result := CallWindowProc(fOldWndProc, VCL.Menus.PopupList.Window, AMsg.Msg, AMsg.WParam, AMsg.LParam);
{│}   if AMsg.Msg = WM_MENUSELECT then begin
{│}     menuItem := nil;
{│}     Msg := TWMMenuSelect(AMsg);
{│}     if (Msg.MenuFlag <> $FFFF) or (Msg.IDItem <> 0) then begin
{│}       for MenuIndex := 0 to PopupList.Count - 1 do begin
{│}         menuItem := FindItemForCommand(PopupList.Items[MenuIndex], Msg);
{│}         if menuItem <> nil then
{│}           break;
{│}       end;
{│}     end;
{│}     miHint.DoActivateHint(menuItem);
{│}   end;
{│} end;
{└─────────────────────────────────────────────────────────────}
end.

Sunday, December 14, 2014

Software Built With Delphi Celebrates 20 Years

I am pleased to announce the release of Credit Card Math 2014, a program written with Delphi XE4.

When I started this project I had just upgraded to Delphi 2010. If you go back and read my first blog post I mentioned one of the reasons for upgrading to Delphi 2010 was "I need to bring my products up to date (no more 640 X 480 windows) etc." 

It's hard to believe that it's been five years since I first mentioned I needed to upgrade my software. Over the past five years I've learned a lot. I've made a shit-load of mistakes. I've developed new coding habits. I've discovered new components. And most importantly I made a bunch of new friends in the Delphi community.

I still have two other software products that need to be updated. I do not believe it will take me five years to upgrade each of them.

I would like to thank the following people, who's software components helped me with my project:

Ray Konopka, Raize Components
Tim Young, ElevateDB 
Boian Mitov, Basic Video 
Nard Mosely, ReportBuilder
Jordan Russell, Inno Setup

Here are some screen shots of Credit Card Math from 1994 - 2014

Credit Card Math 2014: Delphi XE4
Credit Card Math 2004: Delphi 5
Credit Card Math 1998: Delphi 3
Credit Card Math 1994: Turbo Pascal 5.5
Credit Card Math 1994: Turbo Pascal 5.5

Semper Fi,
Gunny Mike



end.

Wednesday, September 10, 2014

Taking the Mystery out of ListView Column Display

Here is a great article about how to display your data in columns using a ListView. Marjan does a fantastic job explaining how to modify the ListView so it displays your data in a nice column display. I'm definitely using this the next time I have a need.

Thank you Marjan!

How to get a ListView to display your values in columns

Enjoy - Semper Fi,
Gunny Mike
end.

Sunday, July 13, 2014

Video: Effectively Using Raize Components by Ray Konopka

I forgot what the RzMenuController from Raize Component did so I went back and watched the video Ray did at CodeRage 7 to remind me. Then I decided to make this list of links that jumps to a specific item for the next time I forget how to do something with one of these controls.

Effectively Using Raize Components by Ray Konopka
  1. Edit Button (4:04)
  2. Menu Button (5:55)
  3. Menu Controller (7:18)
  4. Tray Icon (9:26)
  5. Line Component (11:29)
  6. Progress Display (12:24)
  7. LED Display (14:27)
  8. DBGrid (15:35)
  9. Track Bar (19:23)
  10. Radio Group (24:42)
  11. Persistence Property Store (27:05)

Enjoy - Semper Fi
Gunny Mike
end.

Friday, July 11, 2014

How to Replace Global Variables by Using a Static Class

One of the first things I used to do when creating a new Delphi application was add a copy of the almighty global.pas unit to the project. I'd immediately go in to this file and start tweaking this and tweaking that so it would work with my new application. And, I made sure to ALWAYS add Globals to the uses clause of every new form I created.

My Delphi buddy Bob White, who is Scottish and speaks with a very heavy brogue, called his "Globs". Which stood for globs.pas. I remember him saying, "The programmer's life. Another day, another global." It sounds really cool with his Scottish accent.

Anyway, I thought this was the normal way of doing stuff. I thought every Delphi programmer did this. I never challenged it. Not ever.

Now, as I'm re-learning Delphi all over again for the first time, I hear several Delphi people, in the various Delphi hangouts, say stuff like, "Never use global variables" and "Pretend like global variables don't exist".

I'm thinking to myself... "Okay how the heck do you program if you can't use global variables?"

So, last weekend learned how to replace global variables in my Delphi application by using what is called a static class. It turns out that a static class can simply exist without having to be instantiated. That is pretty cool.

A static class can have constants, variables, functions and procedures. Its like having global variables on steroids. I have replaced my globasl.pas file with a file called ApplicationInfo.pas. I've included a copy of this file below.

This is a fairly new concept for me and it will no doubt go through some changes and refactoring. But so far, I'm liking it.

Here's a couple ways I'm implementing the use of my TAppInfo static class.


The cool part is the Intelisense... I just type TApp and hit [Ctrl] + [Space] and I can pick the item I want. No more "Globs" for this Marine!

ApplicationInfo.pas

Enjoy - Semper Fi,
Gunny Mike
end.

Sunday, July 6, 2014

Just had to share - XE4 includes Beyond Compare

Wow, I just discovered that Delphi XE4 comes with Beyond Compare.

I right-clicked on the project-name from within Project Manager with the intent of choosing the Show in Explorer option when I noticed the Compare option at the bottom. I was pleasantly surprised to see Launch Beyond Compare.

There are two ways to launch Beyond Compare from within the IDE:

 

Makes me think I should spend more time exploring the IDE.

Enjoy - Semper Fi,
Gunny Mike
end.

Friday, July 4, 2014

Choose the Right Folder for Your Application Data

I'm in the process of updating an older program that will now use a local database. I followed my typical "old school" habits and quietly went about my way thinking "I'll just plop the database in a folder called Data that resides in the same location as the exe file. No big deal."

I figured, I'll just use the reliable ExtractFilePath(Application.ExeName) to get the location of where this Data folder needs to go. Right?

Wrong!

I had forgotten to think about how Delphi's "debug" and "release" paths will play into this scenario. Not to mention 32Bit and 64Bit targets. I'm only focused on creating a Windows product at the moment, so for me this means there are a minimum of five paths:

Source
Source\Win32\Debug
Source\Win32\Release
Source\Win64\Debug
Source\Win64\Release

I know I could use "Post-Build" commands (Project > Options > Build Events) to make sure the files are copied from the $(PROJECTDIR) to the $(OUTPUTDIR). However, I was thinking that this is not a very efficient way to go about it. Did I really want to have five copies of a 140MB database cluttering up my hard drive. The answer is no.

So I posed the question "Looking for best practice for using single-user local database." to the Delphi Community on Google+ (https://plus.google.com/u/0/105522328114529031567/posts/Q8go8eWRAfz)

I received several comments and the consensus was to use an application specific subfolder of CommonAppData. Fair enough. CommonAppData it is. What the heck is CommonAppData?

I tend to be a "Show Me" guy I decided to dive into this head long and found out that CommonAppData actually refers to the folder called C:\ProgramData.

Then I wondered what all the other "AppData" type folders were. So I wrote a simple little program to help figure this out. It turns out there are 17 different AppData folders on my computer. I've included a copy of my program for you to use.

AppData Only: Sorted by Path Column

DFM:
object Form1: TForm1
  Left = 0
  Top = 0
  Caption = 'Paths'
  ClientHeight = 411
  ClientWidth = 804
  Color = clBtnFace
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'Tahoma'
  Font.Style = []
  OldCreateOrder = False
  OnResize = FormResize
  OnShow = FormShow
  DesignSize = (
    804
    411)
  PixelsPerInch = 96
  TextHeight = 13
  object StringGrid1: TStringGrid
    Left = 16
    Top = 39
    Width = 772
    Height = 354
    Anchors = [akLeft, akTop, akRight, akBottom]
    ColCount = 3
    FixedCols = 0
    Font.Charset = DEFAULT_CHARSET
    Font.Color = clWindowText
    Font.Height = -11
    Font.Name = 'Tahoma'
    Font.Style = []
    Options = [goFixedVertLine, goFixedHorzLine, goVertLine, goHorzLine, goRangeSelect, goFixedRowClick]
    ParentFont = False
    TabOrder = 0
    OnFixedCellClick = StringGrid1FixedCellClick
  end
  object Button1: TButton
    Left = 16
    Top = 8
    Width = 75
    Height = 25
    Caption = 'Close'
    TabOrder = 1
    OnClick = Button1Click
  end
  object Button2: TButton
    Left = 97
    Top = 8
    Width = 75
    Height = 25
    Caption = 'Get Folders'
    TabOrder = 2
    OnClick = Button2Click
  end
  object CheckBox1: TCheckBox
    Left = 184
    Top = 12
    Width = 97
    Height = 17
    Caption = 'AppData Only'
    TabOrder = 3
    OnClick = Button2Click
  end
end


Program:



Enjoy - Semper Fi,
Gunny Mike
end.

Tuesday, May 20, 2014

Changing the Cursor in FireMonkey

I just watched a video on How to Change the Cursor in FireMonkey by Alister Christie. As I watched this video I learned just how much of a Delphi noob I really am. I had no idea you could go from in-line code to class to interface.



Thank you Alister for a great video and mind-opening experience.

Semper Fi,
Gunny Mike
end.

Friday, May 16, 2014

Make the Most of EMBT's DocWiki

I'm just getting ready to explore chapter 3 of Cary Jensen's Delphi in Depth: ClientDataSets and I stopped to research one of the DataSetProvider options - poFetchDetailsOnDemand.

So, I highlighted the poFetchDetailsOnDemand option in the Object Inspector and pushed F1. It brings up the woefully inadequate local help reference. I was expecting to see a list of all the options with their associated meanings.

Then I googled delphi poFetchDetailsOnDemand, not what I was looking for.

So then I googled site:docwiki.embarcadero.com poFetchDetailsOnDemand

Google Search Syntax:
http://google.com/search?q=site%3Adocwiki.embarcadero.com+poFetchDetailsOnDemand

And... poof... perfect... just what I was looking for.

EMBT should redirect the F1-key to do a web search on their DocWiki and do away with the local help.

Enjoy!

Semper Fi,
Gunny Mike
end.

Thursday, April 17, 2014

Are Your Software Sales Where They Should Be?

As an Independent Software Vendor running a one-person, part-time business I'm always wondering if sales are where they should be. If I'm honest with myself I say "No". Trying to understand why can be a very difficult.

I rediscovered this article called "If No Independent Developers Are 100 Times Smarter Than You, Then Why Do Some Get 100 Times the Results?" written by Steve Pavlina when he was President of the Association of Software Professionals.

I remember reading Pavlina's article about 10 years ago and thinking to myself this is something that should be read and re-read often. Unfortunately, I forgot to bookmark the article back then and had a hard time finding it.

Last year I joined the ASP and found this article on one of the resource pages. It's still a good read.

http://asp-software.org/www/misv_resources/business-articles/results/

Enjoy!

Semper Fi,
Gunny Mike
end.

Sunday, March 9, 2014

Get More out of StackOverflow

It's no secret that StackOverflow or SO as it's commonly referred to is one of the best resources for Delphi enthusiasts. We all have some favorite questions, favorite answers and favorite users out there.

What makes StackOverflow so useful are tags. Tags are the single most important feature. Here is a snippet of what you see when you search tags for Delphi:

StackOverflow Tag Search - Delphi


If you mouseover a tag there is a little pop-up that gives a description of the tag along with some very interesting links. One of the most interesting links is the "top users" link. This "top users" link is how you can get more out of StackOverflow.

By following this link you get a list of which users have answered the most questions and which users have asked the most questions relating to this tag. By drilling down onto the users profile, you can see all the answers and questions this user has participated in.

You can very quickly build a list of your favorite StackOverflow Delphi users. Reading answers by these users will most definitely increase your knowledge about Delphi.

Delphi Tags Top Users
http://stackoverflow.com/tags/delphi/topusers
http://stackoverflow.com/tags/delphi-xe5/topusers
http://stackoverflow.com/tags/delphi-xe4/topusers
http://stackoverflow.com/tags/delphi-xe3/topusers
http://stackoverflow.com/tags/delphi-xe2/topusers
http://stackoverflow.com/tags/delphi-xe/topusers
http://stackoverflow.com/tags/delphi-2010/topusers
http://stackoverflow.com/tags/delphi-7/topusers

FireMonkey Tags Top Users
http://stackoverflow.com/tags/firemonkey/topusers
http://stackoverflow.com/tags/firemonkey-fm3/topusers
http://stackoverflow.com/tags/firemonkey-fm2/topusers

Semper Fi,
Gunny Mike
end.

Saturday, March 8, 2014

Delphi Product and Compiler Versions Quick Reference

I was doing some research on Delphi ClientDataSet QC issues at http://qc.embarcadero.com/ and noticed that the Delphi Product Versions are reported as 18.0, 16.4, etc. When an issue is resolved they show the Resolved in Build as XE5 or sometimes they show it as a number such as 17.0.

When I think of Delphi versions I think of XE5, XE4, D7. I don't think of 19, or 18, or 7. Here is an Embarcadero quick reference webpage that lists all the different Product versions for Delphi.

http://docwiki.embarcadero.com/RADStudio/XE5/en/Compiler_Versions


Semper Fi,
Gunny Mike
end.

Tuesday, January 14, 2014

Embarcadero's Upgrade Policy is Deceiving

I am so frustrated and angry with Embarcadero right now. You have no idea how angry I am. Embarcadero's upgrade pricing policy is deceiving.


I upgraded to XE4 Enterprise from D2010 Professional in May of 2013. I blogged about my decision on May 19, 2013. (You can read about it here)


My upgrade decision was mostly made based on Embarcadero stating that the upgrade to XE4 is only valid for users of D2010 and higher. I did not want to miss out on an opportunity. It only stood to reason that when XE5 came out Embarcadero would only allow upgrade pricing from XE and higher.


Like all of you, I received all the year end marketing emails from Embarcadero. Needless to say, I did not take advantage of these year end offers.


I continued to receive upgrade notifications from Embarcadero. So, I decided to follow the embedded links within the email and now I discover that Embarcadero is allowing upgrades to XE5 to users of D2009 and higher.


THIS IS AN OUTRAGE


If I had waited a few short months I could have spent my upgrade money and received XE5. Now, I have XE4 Enterprise and it's going to cost me another 1,500 dollars to upgrade to XE5. This has got me so angry I don't know what to do. (I'm one pissed off Marine)


I'm a die-hard Delphi fanatic like most of you are. I have a love/hate relationship with Delphi mainly because it takes so dang long to learn how to do something in Delphi and after you figure out how to do it you say to yourself... "It shouldn't have taken that long."


I'm starting to really resent Embarcadero for what I consider to be deceptive marketing and upgrade policies.


I am not a happy camper right now.


Gunny Mike
end.