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/