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:
Gunny Mike
end.

Very nice!
ReplyDeletePossible further development (feel free to ignore :) ):
* Option to see the current setting and the default setting?
* Expand to show all CSIDL values (see: http://msdn.microsoft.com/en-us/library/windows/desktop/bb762494(v=vs.85).aspx) ?
* Expand to include SHGetKnownFolderPath (http://msdn.microsoft.com/en-us/library/windows/desktop/bb762188(v=vs.85).aspx) and it known folders (http://msdn.microsoft.com/en-us/library/windows/desktop/dd378457(v=vs.85).aspx) ? I know that is one is a bit different but I think it would be handy also.
Alternatively you may also create a symbolic link of your Data folder to your Release and Debug folders, so that the Data folder can still be made relative to your executable even while debugging :)
ReplyDelete@Chee Meng - I've never heard of symbolic references. Whaere can I learn more? Please don't "let me google that for you". I'd rather you sent me to specific references you feel are worthy. :-)
DeleteSorry Riley, I did not get notification for reply earlier.
DeleteSymbolic links have been used for a long time in *nix systems, to avoid data duplication… and also for easier version control of executables/shared libraries. For instance you may have a lib_ssl098.so and a lib_ssl099.so, and a symbolic link called lib_ssl.so that currently points to lib_ssl099.so. That way, new compilations will refer to lib_ssl.so that will always point to the latest file, while at the same time you may still directly reference older versions if you want to. And when you get a new file, say, lib_ssl100.so, you then point lib_ssl.so to the latest file and again, future compilations will use the latest file. In *nix and OSX you may achieve that with the “ln -s” command.
In Windows, you may use the mklink command from the command prompt, or the CreateSymbolicLink[Transacted] API calls. http://msdn.microsoft.com/en-us/library/windows/desktop/aa363866(v=vs.85).aspx
Wikipedia is still a good source of reference http://en.wikipedia.org/wiki/Symbolic_link and perhaps even this quick premiere http://linux-blog.org/creating-symlinks-how-and-why/