Check installed Excel version and launch it - c#

I am trying in my application to launch Microsoft Excel with specific arguments (ie. additional xla & xll).
For now it works fine because all of my users only have Office11 (=2003) installed.
My company is going to switch to Windows 7 & Office 2010 and I logically can't launch any excel since the .exe is not located in C:\Program Files:\Microsoft Office\Office11\EXCEL.EXE
I ran a quick check in the registry to see that I can definitely check what version is currently installed. There are also plenty of articles explaining how to get the currently installed Office version.
However, I'd like to know if it is possible to find anything (such as a good registry key) directly giving me the .exe path so as to launch Excel.
Using my current machine (Win XP x86, Office11), I can find it in HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Office\11.0\Excel\InstallRoot
Using this key I can, basically, find a workaround to get the actual path. Problem: there is no such key in Windows 7's registry with Office 2010 (= Office 14) installed.
Do you guys know any way to launch the currently installed excel from C#?
FYI, here is the current code section, launching Office11 from a x64 / x86 machine:
private void LaunchExcel(string arguments)
{
if (!Is64BitsOS())
{
Process process = new Process();
process.StartInfo.FileName = "excel";
process.StartInfo.Arguments = arguments;
process.Start();
}
else
{
Process process = new Process();
process.StartInfo.FileName = "c:/Program Files (x86)/Microsoft Office/Office11/excel.exe";
process.StartInfo.UseShellExecute = false;
process.StartInfo.Arguments = arguments;
process.Start();
}
}
Any ideas to make this code more generic?

If you start Excel to open an Excel file, you can start a Process with the Excel file as FileName and let the Windows shell do all the work to find the associated application. You'd need an exception handler, obviously.
This would make you independent of Office and Windows versions and registry keys.
Otherwise you could take a different approach and find the associated application, like here.
The point of these suggestions is: presently, you have to change your code as soon as a new Office version is installed or a different Windows version is used, while there is a way to avoid these dependencies.

The 32 bit version of Excel 2010 running on a 64 bit version of Windows (XPx64,Vistax64,Win7x64) will have the following key.
I think this is the key you are looking for
HKLM\SOFTWARE\Wow6432Node\Microsoft\Office\14.0\Excel\InstallRoot
The 64 bit version of Excel 2010 running on a 64 bit version of Windows (XPx64,Vistax64,Win7x64) will have the following key
HKLM\SOFTWARE\Microsoft\Office\14.0\Excel\InstallRoot
copied from here

Related

Installation of development and production versions on the same computer

I have a stable production version of software which always has version number "1.X.0". We don't have any testing environment so I created a development version with version number "1.X.Y" for testing purposes. I test this version on production computer before releasing new production version (1.X+1.0)
This works fine, there are safety measures in place so that they cannot get mixed up. I also created automatic update for both versions using
startInfo.Arguments = string.Format("/passive /norestart /i \"{0}\" TARGETDIR=\"{1}\"", msiPath, installDirectory);
installDirectory is different for production and development version.
The problem is this:
The upgrade code is the same for both versions. I don't want to switch between upgrade codes.
I also set RemovePreviousVersion to false, because I don't want to have version 1.X.0 removed, when installing version 1.X.Y.
Is it possible to have versions 1.X.0 and 1.X.Y on the same computer at the same time and when version 1.X.0 gets upgraded to version 1.X+1.0, only 1.X.0 is uninstalled? The same should apply for 1.X.Y version.
Or is there a better way to handle this?
Thank you
I would strongly recommend using a virtual machine to test installation and upgrades of software. If you have pro or enterprise versions of windows you already have access to HyperV. This has several advantages:
You have a known environment, either a clean windows install, or in combination with the software of your choice.
You can easily revert the VM to a previous known state.
You can keep multiple VMs or snapshots of different versions.
You can test different operating systems in a easy way.
You can limit memory and processor capacity without affecting your main workstation.
You can install network limiting tools without affecting your main workstation.
You can, and should, still run and test development builds of the software on your own workstation since this simplify debugging. While VMs are more appropriate when doing "release" tests.
I found the solution for having 2 or more different versions of the same software installed at the same time and updating them automatically.
First I find the version I am currently using with
var version = Assembly.GetExecutingAssembly().GetName().Version;
I then compare that to the version of .msi file which is in a update folder on server (there are production and development folders). If the .msi version is higher than installed version, the upgrade begins.
First I install the new software in the same folder using
startInfo.Arguments = string.Format("/passive /norestart /i \"{0}\" TARGETDIR=\"{1}\"", path, installDirectory);
var process = System.Diagnostics.Process.Start(startInfo);
process.WaitForExit();
Then I uninstall only the version I opened.
I find the product code of that specific version using below code (I found the code in Windows GUID or Application List answer and modified it a bit)
private string GetProductCode(string programName, string version)
{
StringBuilder sbProductCode = new StringBuilder(39);
int iIdx = 0;
while (
0 == MsiEnumProducts(iIdx++, sbProductCode))
{
Int32 productNameLen = 512;
StringBuilder sbProductName = new StringBuilder(productNameLen);
MsiGetProductInfo(sbProductCode.ToString(),
"ProductName", sbProductName, ref productNameLen);
if (sbProductName.ToString().Contains(programName))
{
Int32 installDirLen = 1024;
StringBuilder sbVersionString = new StringBuilder(installDirLen);
MsiGetProductInfo(sbProductCode.ToString(),
"VersionString", sbVersionString, ref installDirLen);
if (version.Contains(sbVersionString.ToString()))
{
return sbProductCode.ToString();
}
}
}
return null;
}
and run
startInfo.Arguments = string.Format("/passive /norestart /x \"{0}\"", productCode);
System.Diagnostics.Process.Start(startInfo);
At the end there are still 2 installed version of the softare and only one was updated.

Restore Previous State of app on database migration failure (ClickOnce)

I want to restore previous version of C# application published using ClickOnce, if database migration fails because database wont be latest and it will not support latest version of application.
Details
I am developing an app which will be used locally in remote areas where internet is not available. A person will update his/her app every once in a while by getting internet somehow and then will deploy the app on local network. From there every one will be able to get the updated version of app. What I want now is to use database migration using this app and if the app fails It should restore to previous version. I have already used FluentMigrator for database migration and have used ClickOnce to deploy the app. I have also gone through almost every link over here to see how can I do it. I now know that its not possible using ClickOnce. Can anybody tell me some other way or may be some kind of hack?. I am using ClickOnce because of its auto update feature so don't really want to lose that functionality now. Any help will be appreciated.
FluentMigrator keeps track of current version in the database. It also keeps track of latest version in the current app version. Run Migrator function and check if the latest version of Migration files in the current version is equal to the latest version stored in a database. If both are equal then Migration was successful. If they are not equal then you can run the cmd command to directly open (remove or backup) window of the control panel and go to the previous version. This is the best you can do to revert to the previous version using ClickOnce.
try {
new MigrationsWrapper(AppManager.ConnectionString).MigrateToLatestVersion();
}
catch (Exception ex)
{
}
LatestVersionNumber = new MigrationsWrapper(AppManager.ConnectionStringADO).LatestVersionNumber;
CurrentVersionNumber = new MigrationsWrapper(AppManager.ConnectionStringADO).CurrentVersionNumber;
if (LatestVersionNumber > CurrentVersionNumber) {
string applicationName = ConfigurationManager.AppSettings["ApplicationName"].ToString();
string uninstallString = GetUninstallRegistryKeyByProductName(applicationName);
if (uninstallString != string.Empty) {
System.Diagnostics.Process process = new System.Diagnostics.Process();
System.Diagnostics.ProcessStartInfo startInfo = new System.Diagnostics.ProcessStartInfo();
startInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
startInfo.FileName = "cmd.exe";
startInfo.Arguments = "/c " + uninstallString;
process.StartInfo = startInfo;
process.Start();
}
} else {
// Successfull
}
So, you want to run previous version of the app if some problem happen during execution.
I don`t know solution for ClickOnce, but there is analogue for it - Squirrel.
Bad news that Squirrel has no straight solution too, but it phisically stores previous version of app and you can run it and it works (I just checked it on my app).
So, there is a strategy:
Migrate to the squirrel (they have a tool for it)
in case of emergency - calc path to the stored previous version and run it. Relative path should be like "../app-1.1.1/myApp.exe"
But there is one thing to keep in mind. Squirrel stores previous version only if it upgraded app from it. There is no prev version after first install.
Good luck.
From the description the different versions of the application are sharing a single database. As a new version of the application goes live on the machine it needs to patch/migrate a shared database. If that fails the application doesn't install. Let's hope it fails without corrupting the database also.
There are clickonce events that can be hoocked into. Create a Custom Installer maybe.
https://msdn.microsoft.com/en-us/library/system.deployment.application.applicationdeployment_events.aspx
https://msdn.microsoft.com/en-us/library/system.deployment.application.applicationdeployment.aspx
Publishing ClickOnce Applications
https://msdn.microsoft.com/en-us/library/748fh114.aspx
Walkthrough: Creating a Custom Installer for a ClickOnce Application
https://msdn.microsoft.com/en-us/library/dd997001.aspx
Hope that's helpful.

How can I conditionally run my program in 64 bit or 32 bit mode based on external resources?

There are a few questions (and unwanted answers) all over the forums about Microsoft.ACE.OLEDB.12.0 provider not being registered on the local machine, like this one. The gist of the problem, how I understand it, is that the application will look for the provider on the same platform as what the application is running on. So if your computer is 64 bit and the provider 32 bit, then there will be a mismatch if you don't compile the application to run in 32 bit mode.
Most answers effectively deal with this by installing the appropriate data components for the current platform. Other suggestions are to compile for whichever platform the data components are available.
I am developing an app using PCs running Windows 7, 8 and 10, all 64 bit, depending on where I am, but some have older versions of Office and others newer versions. This causes me to have to change the platform for which I compile depending on the PC I currently work on. While this is no problem for me, personally, I foresee this causing headaches for the end users not being able to run the program.
Trying to avoid asking users to install other components on their computers; is there a way I can tell the program to check the platform availability of the database provider and then run in that mode? Might it be possible to create 32 bit and 64 bit extensions of the database module and load the appropriate one regardless of the mode the main program is running in?
EDIT:
I just tried to compile my database extensions on different platforms Whichever one that is not the same platform as the application causes an exception when being loaded saying that I am attempting to load an assembly from a different platform. So I guess I'm out of luck with my option 2...
You can use CorFlags utility to modify your executable on target machine, after you will detect which mode it needs to run.
First ensure that your main exe is compiled under any cpu with Prefer 32 bit flag not set. Now when application is started you need to check if we are in 64-bit process or not, and also check your dependencies (this I won't cover - I don't work with OLEDB). If you found mismatch (say you are running in 64-bit process but your dependencies are 32-bit) - you need to run external process to modify your main executable and then restart it. Easiest way to do it is via simple cmd script, like this (in this example my main exe is called ConsoleApplication3.exe):
:start
start /wait "" "C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.6.1 Tools\CorFlags.exe" ConsoleApplication3.exe /32BIT+
if errorlevel 1 (
goto start
)
start "" ConsoleApplication3.exe
Note that this is just example and if something goes wrong it will fall into endless loop, adjust to your requirements. What this script does is just updates your exe using CorFlags tool to run in 32-bit mode, then starts your main exe.
Right after starting your application, you might do the following check:
static void Main() {
if (Environment.Is64BitProcess) {
// here you also check if you have dependency mismatch, and then:
Console.WriteLine("Running in 64-bit mode. Press any key to fix");
Console.ReadKey();
// run script (here we assume script is in the same directory as main executable, and is called fix-mode.cmd
var process = new Process() {
StartInfo = new ProcessStartInfo("cmd.exe", "/c call fix-mode.cmd")
};
process.Start();
// here you should exit your application immediatly, so that CorFlags can update it (since it cannot do that while it is running)
}
else {
// after restart by our script - we will get here
Console.WriteLine("Running in 32bit mode");
}
}
Note that this tool (CorFlags) is available only with Visual Studio so you may want to pack it together with your application (might be not available on remote machine).

Uninstalling a previous component before installing a new one using VS 2005 Setup Project

I have a Custom Action that should execute during the Install portion of an .msi setup. I have a previous version that was installed using InstallShield (which was overkill) and wanted to move to the simpler VS Setup Proj because I do not require all the control that an .isproj provides. However, doing a straight install with my new .msi seems to install side by side with the previous version. Here's what I have found out so far:
I have my product ID
I have written code that will uninstall the previous version through creating a process that uses MsiExec.exe (code will follow)
Tried implementing the custom action to uninstall during setup but it seems you can only have one instance of MsiExec.exe running at a time.
Have been to this post (http://stackoverflow.com/questions/197365/vs-setup-project-uninstall-other-component-on-install), which didnt help.
Custom Action code:
//Exe used to uninstall
string fileName = "MsiExec.exe";
//Product ID of versions installed using InstallShield
string productID = "{DC625BCF-5E7B-4FEF-96DD-3CDBA7FC02C1}";
//Use /x for uninstall and use /qn to supress interface
ProcessStartInfo startInfo = new ProcessStartInfo(fileName, string.Format("/x{0}", productID));
startInfo.WindowStyle = ProcessWindowStyle.Normal;
startInfo.UseShellExecute = false;
//Start process
Process uninstallProcess = Process.Start(startInfo);
//Wait until uninstall is complete
uninstallProcess.WaitForExit();
My hope is to eventually deploy my .msi via ClickOnce, so I am hoping for an option that will fit into deployment option. Currently everything is written in .NET 2.0 and VS 2005, but I do have .NET 4.0 and VS 2010 available to me if there is a new option that works.
Any help is appreciated.
I was able to install over the top of the previous install by making the product code of my setup the same as the code of the older version. Didn't dawn on me to try that because when you create a new version of the setup package, VS always prompts you to change your product code.

Open ACCESS Application thru C# Application on windows 7

Some background:
we have a windows application (c#) that locate in the system try.
that simple application is a basically shortcuts manger for other application and messaging between the workers.
one of the application is an Access 2007 application (connected to sqlserver) - the client works with ACCESS Runtime 2007 (latest version)
THE problem is that we can not launch the Access application correctly from the C# application.
THE problem is only on windows 7 (we don't have vista) - [on XP OS everything works fine)
"correctly" - meaning that the Access application running but the Ribbon Bar is missing some Icons (strange). also some functionality like open the Outlook is not working.
Some more Info:
- IF we put shortcut on the client desktop to the Access application everything ok.
- The C# application have no problem to launch other EXE file.
- The C# application include Manifest file (run as admin on Win 7).
The Original code is very simple (Works only in XP):
System.Diagnostics.Process.Start(AppPath);
The 'Open EXE' code that works (Works on XP and Win7)-[not working with Access Application]
Process Proc= new Process();
Proc.StartInfo.UseShellExecute = false;
Proc.StartInfo.FileName = Application.StartupPath + #"\PasswordManager.exe";
Proc.Start();
We try many codes with no success like [NOT WORKING]:
System.Diagnostics.Process proc = new System.Diagnostics.Process();
proc.EnableRaisingEvents = false;
proc.StartInfo.FileName = sAccPath;// msaccess Path;
proc.StartInfo.Arguments = #"""" + AppPath+ #"""";
proc.Start();
We also try to add [NOT WORKING]:
System.OperatingSystem osInfo = System.Environment.OSVersion;
if (osInfo.Version.Major > 5)
proc.StartInfo.Verb = "runas";
Helppppppppppp!!!
Thanks
I could be wrong on this, but my guess is that it's running in reduced functionality mode due to your not defining a trusted location from which it can run. I don't know how this is done in code, but if you launch A2007, it's on the Office menu under Access Options (I'm posting from menu, as I mostly use A2003 and don't want to wait through the re-registration process).
We uninstall current OFFICE SBE 2007 and Install a newest version of OFFICE SBE 2007.
everything works fine now.
our conclusion is that Office SBE 2007 first version (instaled at client computer) doesn't work well with Access Runtime 2007.
(weird, but work)
David, Thank You very much.

Categories