CodeBetter.Com
CodeBetter.Com
RSS 2.0 via Feedburner
           Do you Twitter? Follow us @CodeBetter

Peter's Gekko

public Blog MyNotepad : Imho { }

August 2006 - Posts

  • Change a database connection string from code

    The connection string to a database should never be hard coded in your application. There is (almost) always a difference between the development and production database server. Besides that IT management should have an easy way to change the configuration. Part of this has been automated by the wizards of Visual Studio. When you add a dataset to a web site the wizard will create a web.config entry for the connection string. That's nice but, as I described in a another post, when you add database code directly to your web site your site will be (sooner or later) toast. My way is to isolate all database code in a class library. But after building the datasets in there it has become harder to change the connection string later on. You have become the sorcerers apprentice. (For those unknown with that story: In there the pupil of a great wizard starts playing around on his own. In the end he's almost killed by a bewitched broom, the wizard himself comes back just in time to save him. The story has been beautiful visualized in Disney's Fantasia where Mickey Mouse is the sorcerers apprentice).

    There is a way out. You can change the connection string of any table adapter at runtime by setting it's Connection.Connectionstring to the desired value. Scott describes how to add this functionality to the code of a dataset component. Which is nice but you have to write this code for every table adapter and you have to set the connection after every instantiation of the table adapter. Which is tedious and a possible source of bugs.

    What the wizards do is store the value of the connection string in a setting of the app. There is a settings page under the properties of a project

    In here settings are stored in name-value pairs. The name is the name of the database; for sqlServer it's the DB name for FireBird (as in the screenshot) the name is the full name of the database file.

    In a web application these settings are stored in the web.config, in a class libray in the app.config file.

    <?xml version="1.0" encoding="utf-8" ?>

    <configuration>

        <configSections>

        </configSections>

        <connectionStrings>

            <add name="DataLibrary.Properties.Settings.C__Documents_and_Settings_Peter_PETERSGEKKO_My_Documents_My_Custoners_DirActivity_DacPro_DACPRO_FDBConnectionString"

                connectionString="port number=3050;charset=ISO8859_1;dialect=3;server type=0;database=&quot;C:\Documents and Settings\Peter.PETERSGEKKO\My Documents\My Custoners\DirActivity\DacPro\DACPRO.FDB&quot;;data source=Farlowella;user id=gebruiker;password=project"

                providerName="FirebirdSql.Data.FirebirdClient" />

        </connectionStrings>

    </configuration>

    What could work is editing this app.config file. But the downside is that you have to maintain besides the web.config an app.config for every class library which works with a database. Which is prone to error.

    To good thing is that you can override the values of these settings from code. When the library is loaded the settings are available in Settings, a property of  the namespace of the library. In this scenario I have a class library which wraps up access to a Firebird database. I add one public method.

    public static void SetConnectionString(string connString)

    {

        const string FBconnectionTEmplate = "port number=3050;charset=ISO8859_1;dialect=3;server type=0;database=\"{0}";

     

        const string SettingsName = "C__Documents_and_Settings_Peter_PETERSGEKKO_My_Documents_My_Custoners_DirActivity_DacPro_DACPRO_FDBConnectionString";

     

        Settings.Default[SettingsName] = string.Format(FBconnectionTEmplate, connString);

    }

    The method has a template for a Firebird connection string. It expects the filename of the Firebird database to use. The setting has a horrible name, that's the fault of the Firebird designer support. When you use sqlserver it will be a simple database name. The name is the indexer to the Settings.Default array. To this I assign the composed connectionstring.

    Now I make one call to this method, passing it a value read form the web.config

    string dbConnString = System.Configuration.ConfigurationManager.AppSettings["dbConnection"];

    ConnectionStringSetter.SetConnectionString(dbConnString);

    After that all table adapters will use the right connection. I have my database wrapped up in a separate layer and still have all configuration in the web.config.

  • Add a custom icon to your (mobile) app

    The devil is in the details. I found this very, very true when doing something as simple as adding a custom icon to a mobile app. This post describes to add a custom icon to a mobile app but the majority of the points are just as well applicable to a full Windows app.

    The Designed for Windows Mobile logo requirements state that an app includes at least two icons: a 16*16 and a 32*32. The larger one is used to display the (required) shortcut in the programs folder, the small one is used in the running programs list, the first item in the PDA's windows menu. (This list does not show in an emulator) . To look well these icons need a transparent background, especially the taskbar looks bad when the background is solid.

    You can create your icons in VS. The icon editor has a color palette, in the top left hand is a small monitor image. All pixels drawn in this color will be rendered transparent.

    Here the icon has the dark-bluish background, in a folder it will be white and in the task bar it will be a blue or red gradient, depending on the user's theme.

    There are several ways to include the icon in the app. The most costly one is to include it as an embedded resource in every form of the application. The icon is a property of a form, you can set it from the property window and edit it in the resx file (which shows up in the solution explorer after selecting "show all files"). Including it in every form makes sense when every form should display it's own icon, but is a waste of (costly mobile) resources in every other scenario. This was another optimization we did in our "from WTF to logo" app. The easiest way to assign the icon is to set it in the application tab of the app's property pages. When building the app the icon will be embedded. There is no need to include the ico file itself when deploying the app.

    There is one final gotcha which did cost me a lot of hair. When installing the updated app on the device, even after a full un-install of the previous version, the application will still display the old icon. It is preserved somewhere in a cache, to see the updated icon you have to reboot the device. I wish I had known that in advance.

    Posted Aug 11 2006, 06:27 AM by pvanooijen with 1 comment(s)
    Filed under:
  • A classic font

    A comment by Eric on Raymonds font post was so hilarious, I just had to give it a try.  My choice is Symbol: (It takes a screen shot to see what that looks like)

    I just knew C# was a classical language :>

    Posted Aug 08 2006, 04:03 PM by pvanooijen with no comments
    Filed under:
  • Deploying Mobile apps the easy way using Inno Setup

    Deploying a mobile application is not as simple as just clicking next, next, finish in a msi wizard. As a result a lot of articles have been written on it, searching the web you will find many. One of the most detailed I found was this one on DevExpress. It works well but requires the .net framework 2.0 to be present on the PC from which to install the mobile app. In my case this was a no-go, I'm in a situation where I cannot count on any version of the framework being present and even the usage of msi files is discouraged. Nevertheless it should be possible to install a mobile CF 2 app according to the Mobile logo requirements, that is using ActiveSync with at the utmost two or three OK clicks from the user. Which was in the end, after a lot of analyzing and searching not only possible but even simpler and clearer than the msi way.

    Deploying a mobile app boils down to these steps

    • Build a CAB file containing the app and it's resources. This is a standard project in VS 2005
    • Write an ini file describing the setup
    • Package cab and ini in a redistributable
    • Unpack the files on the client PC to which the device is connected
    • Fire up the CEappmanager, this is the add/remove programs part of ActiveSync
    • Feed the CE app manger the ini file in the command line

    To do this in an msi requires adding an afterinstall action to the setup. All this action does is fire up the CEappmanager with the ini file in the command line. Adding a custom action to an msi either requires .net 2.0 which supports the Microsoft installer or doing some low-level editing in a finished msi and adding a custom dll to do the action. The first one is easy following the article (but requires the .net 2.0), the second one a tedious nightmare.

    In comes inno setup. Inno setup is freeware and follows a completely different approach to creating a setup. It does so by writing a script. In the script is a list of files to pack, some events to hook into and full custom scripting capability. The nice thing about these scripts is they are in Delphi syntax. Inno setup itself is also written in Delphi, source code is available. Noteworthy is that Delphi versions 2 to 5 are mentioned. I'm not the only one who thinks the real Delphi stopped with that version.

    Inno setup produces one executable which contains the compressed files to redistribute and runs the script. Step by step I'll walk you through a script to deploy a CF application, including the Compact framework itself. Using visual studio I've created a cab file which includes the mobile application and will setup some shortcuts on the device.

    The first [Setup] part of the script describes the setup with the usual info. The app I'm describing here is a PDA extension to TimeWriter, which is a killer app to keep track of your (billable) time. There is a freeware version available, do give it a try.

    [Setup]
    AppName=TimeWriter PDA
    AppVerName=TimeWriter 1.5
    AppPublisher=XSO
    AppPublisherURL=http://www.timewriter.com
    AppSupportURL=http://www.timewriter.com
    AppUpdatesURL=http://www.timewriter.com
    CreateAppDir=yes
    DefaultDirName={pf}\twPDA
    OutputBaseFilename=twPDAsetup
    Compression=lzma
    SolidCompression=yes

    The next section contains the list of files to pack.

    [Files]
    Source: "netcf.ini"; DestDir: "{app}";
    Source: "wce400\armv4\NETCFv2.ppc.armv4.cab"; DestDir: "{app}\wce400\armv4";
    Source: "wce500\armv4i\NETCFv2.wm.armv4i.cab"; DestDir: "{app}\wce500\armv4i";
    Source: "wce500\armv4i\NETCFv2.wce5.armv4i.cab"; DestDir: "{app}\wce500\armv4i";

    Source: "twPDA.ini"; DestDir: "{app}";
    Source: "TimeWriterPDA.cab"; DestDir: "{app}";
     

    The first set is the Compact Framework 2. The three cab files are all targeting the arm processor. Although the compact framework does target other processors, for pocket pc 2003 and later an arm is required. So I can skip the other cab's. The three different cab's target the different versions of pocket pc and windows mobile running on Windows CE 4 and 5. The netcf.ini  describes them. The second set of files is the TimeWriter app with it's ini file. Inno setup will place all these files in the the folder on the client PC.

    Now everything is ready for the CEappmanager to do the real install. The next section in the script fires any application you need after unpacking the files. In my case I want to fire the CEappmanager twice, first to install the Compact Framework, next to install my app.

    [Run]
    FileName: {code:GetCEappManager}; Parameters: {code:GetIniFile|\netcf.ini}
    FileName: {code:GetCEappManager}; Parameters: {code:GetIniFile|\twpda.ini}

    The CEappmanager requires one parameter with the full path of the ini file to process. I don't know where the CEappmager is located and I don't know either where the user has installed the files. In comes the [Code] section, in here you can write full Delphi code to do the work. This code can use functions the inno library but also almost any other Delphi, Win32 or COM (!) function.

    [Code]
    function GetCEappManager(Param : string) : string;
    var Path: String;
    begin
      Path:= '';
      RegQueryStringValue(HKEY_LOCAL_MACHINE, 'SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\CEAPPMGR.EXE','', Path)
      result:= Path
    end;

    function GetIniFile(Param : string) : string;
    begin
      result:= ExpandConstant('"{app}') + Param + '"';
    end;

    The GetCEappManager reads the location from the registry. The getIni file expands the constant {app} to get the directory used for installation and appends the name of the ini file passed in the parameter. Note the quotes, without them a parameter like C:\program files\TwPda\twpda.ini would be interpreted as two command line parameters.

    CEappmanager processes the ini file, which looks like this.

    [CEAppManager]
    Version = 1.0
    Component = NETCF


    [NETCF]
    Description = .NET Compact Framework v2.0
    CabFiles=wce400\armv4\NETCFv2.ppc.armv4.cab,wce500\armv4i\NETCFv2.wm.armv4i.cab,wce500\armv4i\NETCFv2.wce5.armv4i.cab

    It contains a list of cab files. These should located relative to the directory of the ini file. The list in the ini file locates them in the subfolders and should not contain any spaces. The good thing about the CEappmanager is that it knows which cabinet it needs for the specific device. It will only install the one matching the target. To keep a tab on what the appmanager is doing you can add to the registry entry HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows CE Services\AppMgr a DWORD named ReportErrors with the value 1. Some sources state that passing /t in the commandline has the same effect. I cannot confirm that. Now CEappmanager will pop up dialogs telling which files it has found and also info like this:

    It has found three cab files for CF 2.0. The 0 in front of the third indicates it will install that one. That's the one for my device.

    <update>

    Instead of firing the CEappmanager twice you can pass both ini files in one go. This will change the [Run] section to

    [Run]
    FileName: {code:GetCEappManager}; Parameters: {code:GetIniFile|\netcf.ini} {code:GetIniFile|\twpda.ini}

    This undocumented feature probably explains why passing /T as a debugging parameter does not work. /t is seen as a file.

    </update>

    Having run CEappmanager my app and the needed CF 2 is up and running.

    This whole setup script depends totally on the CEappmanager. In case ActiveSync is not installed the appmanger will not be there either and the whole setup is useless as there is no connection to the device. To cancel the script in such a scenario there's the InitializeSetup event. Also part of the [Code] section. It's a boolean function telling to proceed or cancel.

    [Code]
    function InitializeSetup() : boolean;
       var Path: String;
    begin
    Path:= '';
    RegQueryStringValue(HKEY_LOCAL_MACHINE, 'SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\CEAPPMGR.EXE','', Path)
    if Path = '' then
       begin
       MsgBox('Activesync not found !', mbError, MB_OK);
       result:= false;
       end
    else
       result:= true;
    end;

    You cannot use the other script functions in the section, so the code to dive into the registry has to be duplicated. But the way to fire up a dialog is cool.

    There are so many more things you can do with Inno Setup. The tool is very intuitive to use and includes even integrated debugging.

    Delphi style, with the exchanged F5 and F9. But instead of wasting more words on it I can only suggest to try it yourself. To get my mobile setup to work took far less and very clear code compared to the msi way. From now on it is going to be part of my toolbox.

    Posted Aug 03 2006, 09:13 AM by pvanooijen with 5 comment(s)
    Filed under:
  • Mobile devices with a VGA display

    In my previous post I talked a little on make your apps work on a 240*240 display size. On the other side of the spectrum are huge PDA's with a VGA (640*480) display. CF 2 applications adapt to these screens automatically using two properties of the form. But a converted CF 1 app looks awful on such a device. To repair this you have to set these properties by hand. They are set in the InitializeComponent  method of the form

    this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F);

    this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;

    The autoscalemode in a converted app has the value of AutoScaleMode.Inherited. After setting it to AutoScaleMode.Dpi you form looks great on a VGA screen. The AutoScaleDimensions give the form a reference size. In a new form this property is introduced by the designer.

    On such a large screen the size of the SIP input panel is different as well. All reference documentation, including the logo requirements, mentions a height of 80 pixels for the SIP. Instead of hard coding that value as I did in the first post you can read the actual height and use that value..

    private void inputPanel1_EnabledChanged((object sender, EventArgs

    {

       if (inputPanel1.Enabled)

          panel1.Height -= inputPanel1.Bounds.Height;

       else

          panel1.Height += inputPanel1.Bounds.Height;

    }

    Now your app will work well on a small and on a big screen, including SIP support.

    Posted Aug 01 2006, 10:47 AM by pvanooijen with no comments
    Filed under:
  • Screen real estate on mobile devices and the SIP

    Over the last months I've been doing more and more mobile apps. The CF framework 2 really rocks and mobile apps which communicate with PC based app are a welcome extension of functionality. This post marks the start of a new post category : Mobile. I'll add my older post on the subject.

    Mobile devices have small screens. 320*240 pixels used to be default but with smartphones and the iPaq mobile messenger 240*240 is becoming a new standard. Another thing eating up screen real estate is the Soft Input Panel, the screen based keyboard. The problem with that is that it steals away the bottom 80 pixels of the screen. Guidelines for mobile apps advise not to use the bottom 80 liner for text based input controls. That would be quite a waste.

    Container controls like a form or a panel have the AutoScroll property. Setting this to true will automatically show up a scrollbar in case the contained controls don't fit. So when you develop a mobile app based on 320*240 forms it will show with a scrollbar on a 240*240 screen. But this autoscroll property does not work with the SIP. Popping up that still covers the bottom of the form. Searching around for a way to solve this you will find information on a resize of the form when the SIP pops up. This does not work either, the resize event of the form does not fire when the SIP pops up. What does work is this:

    • Cover your form with a panel.
    • Set the panel's anchors to top, left, bottom, right. So the panel will always cover the full form, whatever size.
    • Set the panel's autoscroll property to true.
    • Place all the controls on this panel.
    • Add an inputpanel to the form.

    An example form will look like this in VS:

    Add the following code to the input panel's enablechanged event

    private void inputPanel1_EnabledChanged(object sender, EventArgs e)

    {

       const int SIPsize = 80;

       if (inputPanel1.Enabled)

           panel1.Height -= SIPsize;

       else

           panel1.Height += SIPsize;

    }

    The standard size of the SIP is 80 pixels. When the SIP pops up the panel shrinks by 80 pixels. Autoscroll will keep all controls accessible. When the SIP goes away the panelsize is restored. This is the app on a mobile messenger.

    It would be tempting to resize the form itself instead of the panel. This does not work, you cannot change a mobile form from code.

    Posted Aug 01 2006, 07:39 AM by pvanooijen with 2 comment(s)
    Filed under:
More Posts

Our Sponsors

Free Tech Publications

This Blog

Syndication

News