Monday, June 15, 2015

Download Sites Have Become Software Pimps

I have spent the last couple months doing marketing instead of coding. And this weekend I stumbled across this thing called ProductHunt. It's a pretty cool idea check them out on the web producthunt,com or on twitter @ProductHunt.

The way software needs to be marketed today is completely different that it was 20 - 25 years ago. I refuse to become irrelevant so I am learning how to change my thinking and strategy. This weekend several things fell into place and I went on a rant about the current state of downloads and the download websites.

Here is my five minute rant on why I think download sites have become software pimps and how this is effecting all small software developers.

Semper Fi
Gunny Mike


( transcript )

Most download websites are software pimps.

When I went to the ISVCon in 2013 some of the vendors that the ASP got touted their secondary offer programs.

So for those of you who are not familiar with the secondary offer program, it goes like this. You’re not making money through selling of your software. Okay people find it and then they download it from all the different download sites on the web. But what’s your conversion rate? Is it one out of five-hundred. For every three-hundred downloads you get do you get one sale.

So the download sites their trying to make money. And I call them software pimps because this is what they do. They take your software, your a small independent software developer. You spend hours upon hours putting together a piece of software hoping that you can sell it.

Are you going be the next WinZip or whatever. No, you’re probably not but you’re trying. And you don’t want to get your dreams crushed. So lets say you finally get your software completed it’s gone through all the testing. It’s gone through this. It’s gone through that and you’re ready to push it out to the market.

How are you going to distribute it. You use the software download sites. They take your software and your nice pretty install and they wrap a monetization package around it. The secondary offer.

So here’s what happens. They’re a software pimp. They’re turning your software into a whore. Their platform becomes the mattress. Your software is the whore and then they get unsuspecting customers. So they’ve basically ruined the software download process It’s destroyed. No wonder why Google has the unwanted software thing going on.

The ASP tried 10 years ago to create a website called safer downloads that disallowed this kind of crap. But everybody wants their slice of pie. They’re all greedy little bastards who sit there and say okay I’m a download site. I know marketing. But, I can’t create a piece of software if my life fucking depended on it.

But they’re good at putting together websites. They have a list. Who knows how they compiled that list. And then in order to stay alive have to sell advertising. Well regular advertising doesn’t work. So then they create the Ask toolbar which is probably the worst offender that I’ve ever seen in my life.

Do you know how many times at work people have downloaded something and the Ask toolbar automatically gets installed and now you’ve got all this crap happening. Yeah, that is the secondary software offer program.

And then places like download.com. You go to download.com and your your stuff is listed. I remember 25 years ago when I had my first piece of software out there it’s like oh wow it’s on download.com that’s really cool. If you looked at that website 25 years ago to today it’s like what the hell. They got all these big green buttons that say download now, but none of them are for your software.

Someone finds your product. They go to the description page and there’s seven different friggin download buttons on that page. All of them are big green download buttons. The poor customer doesn’t know what the hell to do. Yeah, there is a need for a safer download website. And the problem is who’s going build it.

The ASP has some great ideas. But the ASP is just a very small organization. ProductHunt understands this. ProductHunt created an environment where they’re keeping the marketers out. Why? Because they are going to pollute it. They’re going to turn it into a secondary offer thing and that’s not what we need. We need something like safer downloads.

Yeah. I may have to talk to Suster and ask him. “Hey do you want to throw some money at a website called safer downloads?” Hey Suster. if you’re listening. Do you want to get involved in a website called safer downloads. If you do let me know.

We’ll put the reputation of the ASP behind you’re money. Go to Google and pitch them a safer download website. Where people can go and download software that’s not going to intrude on their computers and small little software developers like me and all the other product hunters out there who are trying to make this stuff  happen, actually can survive in a world that’s greedy.

So, that’s my take on download sites becoming software pimps.

Gunny out!


Saturday, February 7, 2015

Delphi Speed Tip: Create Local Variables Inline On The Fly

Here is another one of my Love Delphi / Hate Delphi nit pics. I love the strong typing aspect of Delphi. I believe you should always define a variable before you use it. I hate it though when you are inside the guts of a procedure or function and you need a new variable. You have to jump up above the begin statement define the variable and then go back to the spot you were just at and continue coding.

Well I just discovered you can create a new local variable inline on the fly and begin usinging it immediately.

I'd like to thank Ron Grove for demonstrating this handy tip in his video.


Enjoy - Semper Fi,
Gunny Mike
end.

Sunday, January 18, 2015

Great Video On Delphi Form/Code Separation

I just watch a great video by David Schwartz a recently appointed MVP. (Congratulations Dave!). Schwartz gave this presentation during Code Rage 9. After watching this video I did some looking around for more stuff by him. I stumbled on his blog (http://schwartzthink.com/) which I will keep tabs on going forward.

I know today is a big football day but find 37 minutes and watch this video it's very good. I just wish I knew what Lambdas and Closures are?



http://schwartzthink.com/coderage-9/

Schartz's Four Part Series on Interacting with Forms in Delphi:
Interacting With Delphi Forms Part 1
Interacting With Delphi Forms Part 2
Interacting With Delphi Forms Part 3
Interacting With Delphi Forms Part 4

Enjoy - Semper Fi,
Gunny Mike
end.

Friday, January 16, 2015

Make Your Software Installs More Professional

I was showing a friend of mine one of the latest programs I just created. He downloaded it and it installed perfectly. I asked him to uninstall it after we got done looking at it. He went straight to the Control Panel - Programs and Features and to my surprise my application was not listed.

I use Inno Setup (highly recommended) for all of my install files. It turns out that you need to include two directives inside the [Setup] section of the Inno Setup script in order for your program to be listed. I'd like to thank TLama from StackOverflow for his answer.

[Setup]
UninstallDisplayName={#MyAppName}
UninstallDisplayIcon={app}\{#MyAppExeName}

Adding unistall information with Inno Setup
TLama
Inno Setup

Enjoy!

Semper Fi
Gunny Mike
end.

Saturday, January 3, 2015

Most Frequently Used Shortcuts By Delphi Programmers

Here is a list of the most frequently used shortcuts by Delphi programmers

Ctrl+Space
Code Completion (window resizeable/sortable)
Video

Ctrl+Shift+C
Class Code Completion at Cursor

Ctrl+Shift+V
Declare Vaiable

Ctrl+Shift+D
Declare Field

Ctrl+Shift+Space
Code Parameter Hints (invoke tooltip help)
Video

Ctrl+J
Code Templates (window resizeable)
Video

Ctrl+Shift+J
Sync Edit
Video

Ctrl+Left Click
Alt+Up Arrow
Code Browsing (requires $YD)

Ctrl+Shift+Up Arrow
Ctrl+Shift+Dn Arrow
Code Jumping Between Declaration/Implementation

Alt+Left Click+Drag
Select Block

Tab
Indent Selected Code
Indent Selected Block

Shift+Tab
Outdent Selected Code
Outdent Selected Block

Ctrl+D
Format Selected Code
Format Selected Block

F9
Run

Ctrl+Shift+F9
Run Without Debugging

F4
Run To Cursor (Build Debug)

Ctrl+F9
Compile

F5
Set/Remove Breakpoint
Video

F7
Trace Into

F8
Step Over

Ctrl+F2
Program Reset

Enjoy,
Gunny Mike
end.

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.