{"id":697,"date":"2010-11-26T12:04:39","date_gmt":"2010-11-26T00:04:39","guid":{"rendered":"https:\/\/www.deltics.co.nz\/blog\/?p=697"},"modified":"2010-11-26T12:04:39","modified_gmt":"2010-11-26T00:04:39","slug":"deploying-without-dbxdrivers-ini","status":"publish","type":"post","link":"https:\/\/www.deltics.co.nz\/blog\/posts\/697\/","title":{"rendered":"Deploying without DBXDRIVERS.INI"},"content":{"rendered":"<span class=\"rt-reading-time\" style=\"display: block;\"><span class=\"rt-label rt-prefix\">[Estimated Reading Time: <\/span> <span class=\"rt-time\">4<\/span> <span class=\"rt-label rt-postfix\">minutes]<\/span><\/span><p>As far as I can tell, as of <em>Delphi 2010<\/em> at least it is impossible to deploy a <em>DBExpress<\/em> application without also deploying at least one <strong>dbxdrivers.ini<\/strong>.  Furthermore, deciding where this <strong>ini<\/strong> file has to go is a minefield, and the <strong>DBExpress<\/strong> architecture smells very badly in this area.<br \/>\n<!--more--><\/p>\n<p>Sadly, this post won&#8217;t contain all the answers to the question it poses since I have not yet found those answers.  The post is in part an effort to find someone with the answers &#8211; if they exist.<\/p>\n<h3>The Context<\/h3>\n<p>One project I am working on is being migrated from <strong>Delphi 2006<\/strong> to <strong>Delphi 2010<\/strong> (ultimately XE, hopefully, but 2010 is where I am at right now).<\/p>\n<p>The application supports connection to a variety of databases, using the DBExpress framework.  In <strong>Delphi 2006<\/strong>, connections were instantiated and configured dynamically.<\/p>\n<p>Never mind whether having configuration parameters maintained in an external configuration file is <strong>A Good Thing<\/strong>\u2122 or not &#8211; the fact is, this was not how the application worked, and it did work very successfully for some years.<\/p>\n<p>Note also that the application is not an internal application but a commercial product, so the extent to which we can dictate the environment in which the application runs is necessarily limited.<\/p>\n<p>Problems were immediately uncovered when we moved this code to <strong>Delphi 2010<\/strong>, and all revolve around <em>DBXDRIVERS.INI<\/em> file, or the lack there-of&#8230;<\/p>\n<h3>Setting DriverName<\/h3>\n<p>First, when setting a value for the <em>TSQLConnection.DriverName<\/em> property, if that value is anything other than an empty string, the property setter now insists on loading information from the <strong>ConnectionFactory<\/strong> for that driver.<\/p>\n<p>In <strong>Delphi 2006<\/strong> this only occurred at design-time, but it is now a behaviour also imposed at runtime.<\/p>\n<p>There is only one <strong>ConnectionFactory<\/strong>, and that is the one driven by the INI file &#8211; <em>DBXDRIVERS.INI<\/em><\/p>\n<p>The result:  If you have any code that sets <strong>DriverName<\/strong> to a non-empty string, you must now have a <em>DBXDRIVERS.INI<\/em> file, and the <strong>DriverName<\/strong> you set must now be a valid a driver name identified by that ini file.<\/p>\n<h3>NOT Setting DriverName<\/h3>\n<p>So perhaps we can avoid this problem by not setting <strong>DriverName<\/strong>, leaving this property empty and configuring the parameters that would be set from the ini file manually ourselves (as we always used to do).<\/p>\n<p>Sadly, this doesn&#8217;t work either.<\/p>\n<p>For whilst you can successfully leave <strong>DriverName<\/strong> unset and set all other relevant properties, things fall apart when you then try to then <em>Connect<\/em> the <em>TSQLConnection<\/em>.<\/p>\n<p>At this point, <em>DoConnect()<\/em> will call <em>CheckLoginParams()<\/em> (unavoidable) and <em>CheckLoginParams()<\/em> contains this line of code:<\/p>\n<pre class=\"brush: delphi; title: ; notranslate\" title=\"\">\r\n if FDriverName = '' then DataBaseError(SMissingDriverName);\r\n<\/pre>\n<p><a href=\"https:\/\/forums.embarcadero.com\/message.jspa?messageID=302637&#038;tstart=0\">Somebody else suggested<\/a> configuring the connection parameters in a <strong>BeforeConnect<\/strong> event, but this changes nothing about the flow of code that reaches this line of code.<\/p>\n<p>Setting <strong>DriverName<\/strong>, even in <em>BeforeConnect<\/em>, will invoke <em>DBXDRIVERS.INI<\/em> validation of the specific value.<\/p>\n<p><strong><em>Not<\/em><\/strong> setting <strong>DriverName<\/strong> will always result in the <em>TSQLConnection<\/em> complaining that the property has not been set when it is eventually connected.<\/p>\n<p>Which is right were we started.<\/p>\n<h3>Giving In To The Inevitable: Deploy and be Damned<\/h3>\n<p>So, it looks like we are forced to provide a copy of DBXDRIVERS.INI with our application.<\/p>\n<p>That isn&#8217;t necessarily <strong>A Bad Thing<\/strong>\u2122.  Having the ability to add support for new drivers to our application could actually be an improvement, so rather than investigate how to avoid deploying <em>DBXDRIVERS.INI<\/em>, I instead set about looking into how to safely and reliably deploy it.<\/p>\n<p>Oh dear.<\/p>\n<p>Oh dear, oh dear.<\/p>\n<p><strong>DBExpress<\/strong> starts to look very shonky when you prod and poke things in this area.<\/p>\n<p>Critical to the whole thing is how <strong>DBExpress<\/strong> locates <em>DBXDRIVERS.INI<\/em>.  This is critical because you have no way to explicitly direct <strong>DBExpress<\/strong> to use a given ini file or even look for <em>DBXDRIVERS.INI<\/em> in a specific location.<\/p>\n<p>It follows it&#8217;s own rules:<\/p>\n<p>1. Look in the application directory.  That is, the directory containing your application EXE file.<\/p>\n<p>In the days of UAC I am sure I don&#8217;t need to spell out why this is not only <strong>A Bad Idea<\/strong>\u2122, but <strong>A Dumb Idea<\/strong>.  <strong>A Very <em>VERY<\/em> Dumb Idea<\/strong>.<\/p>\n<p>2. If no file found in the application directory, use the location stored in the registry key: <em>HKEY_CURRENT_USER\\CodeGear\\BDS\\7.0\\DBExpress\\DriverFilename<\/em><br \/>\n2<br \/>\n<strong>NOTE:<\/strong> You can change the <em>value<\/em> of this key, but you cannot change the <em>name<\/em> of the key.<\/p>\n<p>3. If no registry key is found in <em>HKEY_CURRENT_USER<\/em>, or if the <em>DBXDRIVERS.INI<\/em> file is not found in the location identified by such a key, then look for the same key in <em>HKEY_LOCAL_MACHINE<\/em>.<\/p>\n<p><strong>NOTE:<\/strong> If you use either registry keys to store your <em>DBXDRIVERS.INI<\/em> file location, then you had better be prepared to share your <em>INI<\/em> file with every other <strong>DBExpress<\/strong> application on the machine.  We would rather not have to do that.<\/p>\n<p>But we don&#8217;t want to store <em>DBXDRIVERS.INI<\/em> in the application directory either.<\/p>\n<h3>Where Do We Go From Here<\/h3>\n<p>Ideally we would be able to continue configuring our <strong>TSQLConnections<\/strong> at runtime, dynamically.  Just as we always used to.  We can extend our own application very easily to support additional drivers not known at compile time &#8211; and since we will need to store those configuration details in a database, this would actually be preferable to maintaining an INI file separate\/in addition to that database.<\/p>\n<p>Failing that, we need to be able to direct <strong>DBExpress<\/strong> to use an INI file of our choosing, or at the very least direct <strong>DBExpress<\/strong> to use a <em>DBXDRIVERS.INI<\/em> file in a location of our choice.<\/p>\n<p>These seem like pretty basic requirements to me.<\/p>\n<p>One of which used to be possible, the other which should have been made possible once the alternative was taken away, and ideally in addition to the alternative in the first place.<\/p>\n<p>But, I also have to say that in exploring the code in <strong>SqlExpr<\/strong>, I am not impressed by what I see.<\/p>\n<p>Not one little bit.<\/p>\n<p>It is worrying that these simple, and to me: obvious, design flaws are present in the framework in the first place.<\/p>\n<p>It is downright scary to see the mess that the code is in that implements the design choices that were &#8211; for whatever reason &#8211; made.<\/p>\n<p>Just one example that immediately springs to mind, and doesn&#8217;t need a lot of explanation:<\/p>\n<p><em>TSQLConnectionFactory<\/em> is an abstract base class for all connection factory implementations.  There is only one such implementation &#8211; the one that sits atop the INI file(s).<\/p>\n<p>So it is not obvious to me why the abstract base class contains code to locate and identify INI files, which are supposedly part of the implementation of the specific INI file based derived class.<\/p>\n<p>Other examples include very suspect indentation that smells very badly of incorrect conditional flow control, but it is difficult to say for sure that this is indeed what that indentation indicates, obviously.<\/p>\n<p>Similarly the amount of commented out code (commented out without explanation) is worrying &#8211; such artefacts smell of experimental\/incomplete code in my experience.<\/p>\n<p>But I digress.<\/p>\n<p>The point of this post was specifically around the deployment issues relating to <em>DBXDRIVERS.INI<\/em> and how to avoid those issues or make the best of a bad job.<\/p>\n<p>Any ideas?<\/p>\n","protected":false},"excerpt":{"rendered":"<p><span class=\"rt-reading-time\" style=\"display: block;\"><span class=\"rt-label rt-prefix\">[Estimated Reading Time: <\/span> <span class=\"rt-time\">4<\/span> <span class=\"rt-label rt-postfix\">minutes]<\/span><\/span> As far as I can tell, as of Delphi 2010 at least it is impossible to deploy a DBExpress application without also deploying at least one dbxdrivers.ini. Furthermore, deciding where this ini file has to go is a minefield, and the DBExpress architecture smells very badly in this area.<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"jetpack_publicize_message":"","jetpack_is_tweetstorm":false,"jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":false,"jetpack_social_options":[]},"categories":[4],"tags":[101,122,292,124,123],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_shortlink":"https:\/\/wp.me\/p1TKYv-bf","jetpack_sharing_enabled":true,"jetpack-related-posts":[{"id":624,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/624\/","url_meta":{"origin":697,"position":0},"title":"Another One Bites The Dust","date":"25 Feb 2010","format":false,"excerpt":"Another commercial Delphi component vendor has apparently decided to pursue a direction that no longer involves supporting at least some of their Delphi components on a commercial basis. \u00a0Fortunately in this case they have decided to open source their products. \u00a0So, if you are using the Luxena DBExpress drivers for\u2026","rel":"","context":"In &quot;Delphi&quot;","img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":2298,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/2298\/","url_meta":{"origin":697,"position":1},"title":"The BDE is Finally, Properly (Almost) Dead","date":"05 Sep 2014","format":false,"excerpt":"As of the XE7 release of Delphi\/RAD Studio, the long deprecated BDE is finally dead. And almost properly this time. From the \"What's New in XE7\" page: BDE, our oldest database solution, has reached the final stage of deprecation, and has been removed from RAD Studio. This includes the Bde.DBBdeWeb\u2026","rel":"","context":"In &quot;Delphi&quot;","img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":1097,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/1097\/","url_meta":{"origin":697,"position":2},"title":"EULA Change:  No Client\/Server in XE3 Pro. Not even 3rd Party.","date":"28 Aug 2012","format":false,"excerpt":"I don't enjoy posting this news. I really don't. I had hoped that my next post would be a more positive report following the Auckland leg of the XE3 World Tour this morning (and that will come later today). But I feel this news is so important that it has\u2026","rel":"","context":"In &quot;Delphi&quot;","img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":716,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/716\/","url_meta":{"origin":697,"position":3},"title":"Delphi [Non]Starter Edition: No VCL Source!","date":"03 Feb 2011","format":false,"excerpt":"After an initial welcome (and purchase!) I find myself having to curb my initial enthusiasm. \u00a0Most of the omissions from the Starter Edition, as compared to the Professional and higher editions, make perfect sense and are in fact pretty much what I myself described as appropriate for a \"Community Edition\"\u2026","rel":"","context":"In &quot;Delphi&quot;","img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":735,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/735\/","url_meta":{"origin":697,"position":4},"title":"RAD STUDIO XE2: Launch Event Report","date":"04 Aug 2011","format":false,"excerpt":"Today I was fortunate to be present in Auckland at the World Premier of the launch event for RAD Studio XE2. \u00a0There is so much good to report that I really don't know where to begin, so apologies if this post is a bit of a disorganised ramble. \u00a0But here\u2026","rel":"","context":"In &quot;Delphi&quot;","img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":220,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/220\/","url_meta":{"origin":697,"position":5},"title":"Poll Time Again","date":"23 Aug 2008","format":false,"excerpt":"With Delphi 2009 literally just around the corner, I thought it would be interesting to see how it's impending release is being viewed. As a result, the poll answers are a little wordy this week for which I apologise, but I thought it would be interesting to try and gauge\u2026","rel":"","context":"In &quot;Delphi&quot;","img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]}],"_links":{"self":[{"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/posts\/697"}],"collection":[{"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/comments?post=697"}],"version-history":[{"count":2,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/posts\/697\/revisions"}],"predecessor-version":[{"id":699,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/posts\/697\/revisions\/699"}],"wp:attachment":[{"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/media?parent=697"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/categories?post=697"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/tags?post=697"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}