Friday, November 20, 2009

Installing AccessDatabaseEngine with Application Setup

If you are using Access2007 database in application then you need to have the accessdatabaseengine to make you application work, if MS Office is not installed on the client machine.

You need to perform the following steps to make accessdatabaseengine part of your application setup that installs it along with your application.

1. Download the AccessDatabaseEngine.exe from the following location-
http://www.microsoft.com/downloads/details.aspx?familyid=7554F536-8C28-4598-9B72-EF94E038C891&displaylang=en

2. Include AccessDatabaseEngine.exe in your setup:-
-Open the file system editor of your setup project.
-Add the AccessDatabaseEngine.exe in your application folder.

3. Include an Installer class to your main project if it is not there, and make sure that the RunInstaller attribute is set to true. [RunInstaller(true)]





4. Override the Install method in the Installer class.

public override void Install(IDictionary stateSaver)
{
    base.Install(stateSaver);
}

5. Generate event for the AfterInstall and write the following code in it to install the access database engine.
private void Installer1_AfterInstall(object sender, InstallEventArgs e)
{
    string str = System.Reflection.Assembly.GetExecutingAssembly().Location;
    string accessComponentFile = "AccessDatabaseEngine.exe";


    int indx = str.LastIndexOf('\\');
    str = str.Substring(0, indx);


    System.Diagnostics.Process prc = new System.Diagnostics.Process();
    try
    {
      prc.StartInfo.FileName = str + "\\" + accessComponentFile;;
      prc.StartInfo.Arguments = "/quiet";
      prc.Start();
      prc.EnableRaisingEvents = true;
      prc.Exited += new EventHandler(prc_Exited);
    }
    catch (Exception ex)
    {
      System.Windows.Forms.MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
    }
}

The prc.StartInfo.Arguments = "/quiet"; installs the access database engine in silent mode.

6. Delete the AccessDatabaseEngine.exe from the client machine-

Write the following code in the process exited event of the process defined in the AfterInstall event.

void prc_Exited(object sender, EventArgs e)
{
    string str = System.Reflection.Assembly.GetExecutingAssembly().Location;
    string accessComponentFile = "AccessDatabaseEngine.exe";
    int indx = str.LastIndexOf('\\');
    str = str.Substring(0, indx);

    string FolderPath = str + "\\" + accessComponentFile;
    if (File.Exists(FolderPath))
    {
      try
      {
        File.Delete(FolderPath);
      }
      catch (Exception ex)
      {
      }
    }
}

36 comments:

  1. Hi Yogi I'm new to vb.net and I need to solve this problem in vb.net. Will you post also a vb.net version.
    Thank you and best regards jame from phil's...

    ReplyDelete
  2. Hi...
    Check out the following link - "http://www.developerfusion.com/tools/convert/csharp-to-vb". It is a very good tool to convert code from C# to VB.Net and VB.Net to C#. Happy codeing!

    ReplyDelete
  3. Hi Yogi...
    thank you for your reply...
    your blog is very nice, wish you all the best!:-)

    ReplyDelete
  4. hi yogi,

    i try to convert and i have problem in
    compiling.... an error
    Attribute 'RunInstallerAttribute' cannot be applied multiple times.
    q: how are you going to Set 'RunInstaller' attribute to true?

    thank you
    jame

    ReplyDelete
  5. Hi
    When you add installer class in your project, the RunInstaller arrtibute is already set to true, i.e. [RunInstaller(true)] at the top of installer class. The problem you are getting is because you have set this attribute mre than once. Remove the extra declaration and it should work fine.

    ReplyDelete
  6. Hi Yogi,
    Yes, you are correct, thanks!
    I have it done in converting it to vb.net
    thank you and all the best for you blog.

    jame

    ReplyDelete
  7. Hi Yogi,
    I would like to ask an advice on how to make updates....
    Like in your application you could click to make update with your application for the new version when you have made some changes on you application.
    or when the application launched, it should download the updates and update the installed version.
    C# or VB would help me as guide to accomplish.

    thanks in advance...
    best regards,

    jame

    ReplyDelete
  8. Hi Jame

    It would not be possible now (at least for some days) for me to put blog on this topic. However I try to explain how you can do it.

    1. As you are ready with the updates, keep the files .(exe, .dll etc) on your server, say an FTP location, from where your application will download the updates.

    2. Whenever you put the files on FTP location, also maintain an file say an XML file that contain the information like version of the latest files.

    3. Then you can create a WebService, that will download the required files (based on the version in the XML file) from the FTP location and place in some temp location of your computer.

    4. In your main application provide a link for "Update" that will call the web service and copy in the temp location. [Preferebaly make a seperate application that will call the Web service, so that close the main application while the updation is in process and you can copy the files from temp location to your application folder.

    Hope that will help...

    ReplyDelete
  9. Hi Yogi,
    Thank you for explaining on the steps.
    I will try to follow the steps. Hope I could make it.

    Best regards,

    jame

    ReplyDelete
  10. Hi Yogi,

    I have updated the exe file in XP and Vista programmatically, but I can't file.replace() the exe file in Windows7. Can I ask help from you...I need to replace the exe file from all programs directory in Windows7. I have problem in ACL thing ...its access denied.

    thank you,

    jame

    ReplyDelete
  11. Hi Jame
    I have no really workeed on Windows 7, so unable to give you inputs on this. But I am sure that you will find some solution on the net. Wish you luck..

    ReplyDelete
  12. Hello Yogi,

    thanks for the reply.
    Yes, I will try searching on the sulotion for Win7. for now I will just instruct the User to go to the apllication.exe and run it as administrator so that it can do the auto updates...

    Thank you for always the helps and useful inputs. Wish you all the best for you!

    jame

    ReplyDelete
  13. Hi
    would you please explaine me how to use this installer class more detailed?

    I have added simply a installer class after configuration my setup project, but when I run the setup program, I don't have any Access Database Engine on the target system.

    thank you
    Mo from Germany

    ReplyDelete
  14. Hi Mo
    You need to include the Access Database Engine in your setup project.
    Add this file as explained in step 2. Browse for the file and Add it.
    And then, install the file to the target computer, as explained in step 5.
    If you have any further questions, please give a bit more specific point where you are having problem
    Thanks

    ReplyDelete
  15. Please see this:
    http://mo-morpheus.blogspot.com/2010/09/add-adbe-to-my-c-project.html

    Thanks a lot.
    Mo

    ReplyDelete
  16. hi...nice article.but how to make this installer class work at install time...i have done exactly what u have done, except the installer class file name...please suggest...Thanks

    ReplyDelete
  17. Hi..
    To add installer class in your project (not the setup project, but the project you are going to install), right click on the project -> add new item -> and then choose installer class.
    This class will be used for the intallation event for your setup project.
    Hope it helps.
    Thanks:)

    ReplyDelete
  18. Hi Yogi,
    I have a requirement where
    1.I have to install Access 2010 runtime engine if Access 2007/2010 is not installed in the system.
    2.Drop all the constraints from empty accdb database and copy the data from mdb to accdb database and add back the constraints.

    I developed the windows application with the above requirements. The final requirement is that a setup application (msi) has to be created with the above mentioned requirements.

    I have created the installer classes as you suggested above in this article.since access runtime is installed in silently,ACE drivers are not installed.Therefore connectionstring is not working. Please suggest me how can i implement delete constraints,copy data and add constraints in the installer.cs file.

    Hope you understand my problem.

    Thanks in advance,
    vijay

    ReplyDelete
  19. Hi Vijay

    For disabling and enabling the constraints you may use the following -
    -- disable all constraints
    EXEC sp_msforeachtable "ALTER TABLE ? NOCHECK CONSTRAINT all"

    -- enable all constraints
    exec sp_msforeachtable @command1="print '?'", @command2="ALTER TABLE ? WITH CHECK CHECK CONSTRAINT all"

    But I didnt find reason why you would like to copy the mdb database into the accdb one. The best would be, prepare the accdb database at youe end and ship it with your application setup.
    But any way, tough I have not tried, I think that the connection string should work as by then the runtime for the Access had already been installed. You may write your logic after the "prc.Exited" line. Hope that helps

    ReplyDelete
  20. Hi Jogi Sir,
    Thank you for your reply.

    I tried to check the connection string after quiet mode of installation of Access run time.But It does not work.It throws oledbexeception.

    Any help in this is appreciated.

    Thanks,
    Vijay.

    ReplyDelete
  21. Hi Vijay
    Can yo please share the piece of code that you are trying to execute, and the connection string. Try give as much as information you can provide.

    ReplyDelete
  22. Hi Yogi Sir,
    Please find the code snippet below:
    //Check if Access 2007 or 2010 exists in registry
    private bool IsAccess2007Installed()
    {

    bool retval = false;
    RegistryKey rootKey = Registry.ClassesRoot.OpenSubKey(@"Access.Application\CurVer", false);
    if (rootKey == null)
    {
    retval = false;
    }
    else
    {
    string value = rootKey.GetValue("").ToString();
    //int verNum = int.Parse(value.Substring(value.IndexOf("Access.Application.")));
    string accstr = value.Substring(19, 2);
    int verNum = int.Parse(accstr);
    if (value.StartsWith("Access.Application.") && verNum >= 12)
    {
    retval = true;
    }
    }
    return retval;
    }
    //Install the Access Database runtime engine if access 2007 or 2010 doesnot exist.
    private void InstallEngine()
    {

    string accessComponentFile = strAccessRuntimePath;
    System.Diagnostics.Process prc = new System.Diagnostics.Process();
    try
    {
    prc.StartInfo.FileName = accessComponentFile;
    prc.StartInfo.Arguments = "/quiet";
    prc.Start();
    prc.EnableRaisingEvents = true;
    prc.WaitForExit();

    }
    catch (Exception ex)
    {

    }
    finally
    {
    prc.Close();
    prc.Dispose();
    }
    }

    public override void Install(IDictionary stateSaver)
    {
    base.Install(stateSaver);

    }
    private void DB_Upgrade_Installer_AfterInstall(object sender, InstallEventArgs e)
    {
    OleDbConnection con = null;
    try
    {
    System.Diagnostics.Debugger.Launch();
    string str = System.Reflection.Assembly.GetExecutingAssembly().Location;
    int indx = str.LastIndexOf('\\');
    str = str.Substring(0, indx);
    p_strTargetApplicationPath = str;//System.Reflection.Assembly.GetExecutingAssembly().Location;
    p_strOldMdbPath = p_strTargetApplicationPath + "\\Source.Dat";
    p_strNewAccdbPath = p_strTargetApplicationPath + "\\Destination.accdb";
    p_strAccessRuntimePath = p_strTargetApplicationPath + "\\AccessDatabaseEngine.exe";
    if (!IsAccess2007Installed())
    InstallEngine();
    con = GetNewAccdbConnection();
    GetAllIndexes(con);
    DropFKs(con);
    DropAllPKs(con, dtPKs);
    DropAllPKs(con, dtUKs);
    DeleteData(con);
    CopyData(con);
    AddPks(con);
    UpdateFK(con);

    }
    catch (InstallException ie)
    {
    }
    finally
    {
    // Close database connection

    if (con.State == ConnectionState.Open)
    con.Close();
    }
    }


    Also please suggest me "how to include the msi in a setup project." coz the child msi included also starts installing but finally ends with error saying that "No two installations can be done a time"

    Any suggestions are appreciated.

    Thanks in advance,
    Vijay

    ReplyDelete
  23. Hi yogi sir,
    The following is the conncetion string used:
    public static OleDbConnection GetNewAccdbConnection()
    {
    //if (mCon == null)
    OleDbConnection ocon = null;
    try
    {

    ocon = new OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + strNewAccdbPath + "; user id=;password=;Jet OLEDB:Database Password=xxxxxxxxxxxxxxxxx;");
    if (ocon.State == ConnectionState.Closed)
    ocon.Open();

    }
    catch(OleDbException ex)
    {
    }
    return ocon;
    }
    Thanks in advance,
    Vijay

    ReplyDelete
  24. Hi Vijay
    The code that you gave me looks fine... what you can do is that make sure that in the "Custom Actions", you have specified the Primary Output of you application in the actions for "Install". (and others also if you coded for them). It is necessary to enable the code you wrote in your installer class.

    But if you are able to debug the installer class code, you are already done with it. If this is the case, all I can say is just have a look at the values that are in action in the debug mode and Google for the exceptin resolution. OR please mail me at - "yogeshve@yahoo.com" and ask me if I can contribute. GoodLuck

    ReplyDelete
  25. Hi Yogi

    why i will get this message after the installation but the AccessDatabaseEngine does not installed?

    Usage:
    /extract:path,extracts the contents of the package to the path folder
    /quiet, runs the package in silent mode
    /?, shows this help message

    ReplyDelete
    Replies
    1. Hi, if you include AccessDatabaseEngine in Custom Action, you will get this Error!

      Delete
  26. Hi
    I didnt understood the problem, with the description you have given. But it seems that the "/q" argument is not passed properly. (Pls refer to the code I have provided.)
    If it doesnt help, please provide a bit more descreptive statement, hope I could help.

    ReplyDelete
  27. Yogi,
    I am very interested in implementing this solution as the folks from the Microsoft forum are not very much help. I am failing to understand from a high level how your solution works. I created a windows installer project with my application and supporting files as well as the AccessDatabaseEngine.exe file. All goes well. Upon discovering your solution, I tried to follow your instructions but I am unsure what the connection is between the two projects in the solution. (I am using VB).
    I was unsure what kind of project to add to my setup solution so I just added a windows form project (named AccessInstallation)and of course the startup for the project is Form1. I was able to add an installer class and translate your C# code into VB. I also noticed from your screenshot in step 2 there is something called Primary Output from InstallSample(active) so I added that to the setup project. What I was unable to see is where I can locate and check that RunInstaller attribute is set to true (from step 3).
    So I have these two projects in the solution and when I build, I see setup.exe and the application.msi file produced and I can execute them and it does put AccessDatabaseEngine.exe in the application folder but I suspect the second project (with your code in it) never gets executed. How does it get triggered?

    Thanks for your help, I have never done anything like this before.

    ReplyDelete
  28. Hi JP..
    Actually out of the 2 projects that we are having in the solution, one is the main application project (in your case it is windows form project), and the other one is the setup for packaging and creating the setup for the main project.
    As for the linking between the projects, there are 2 things in picture, one is the "installer class" that you would add to the main project and second, when you add primary output to the setup project, it is actually linking with the main project.
    Infact you should have created the application project first and then adding the setup project for it.
    The "RunInstaller" attribute is in the installer class.
    Thanks

    ReplyDelete
  29. Yogi, Success with one additional step required. It would not trigger until I included a custom action in the Install folder in the setup project for primary output. I posted the VB version in a corresponding Microsoft forum thread: http://social.msdn.microsoft.com/Forums/en-AU/vbide/thread/7d0a3007-531f-4960-bbd8-8caccfb66ec7?prof=required

    Many Thanks!

    ReplyDelete
  30. Hi I have add Installer class but it is not work.
    I want to include AccessDatabaseEngine.exe and installed
    when my set up is run.

    ReplyDelete
    Replies
    1. Hi it works..make sure you didnt missed any steps. If there is problem even then, please send some more details about it.
      Thanks

      Delete
  31. AccessDatabaseEngine.exe /unistall or something silent uninstallation exists ?

    ReplyDelete
    Replies
    1. I am not sure if you can uninstall through installer, may the following link could help you - http://www.symantec.com/connect/forums/accessdatabaseengineexe-aborting-when-called-msi-using-execute-program-installation.
      Otherwise you always have option of removing it from Add Remove Programs

      Delete
  32. Good Job Man! It's working. Thanks

    ReplyDelete