Install app which uses .dll with IExpress Wizard - c#

I have two applications which will be installed by a single executable. The problem I'm facing is that one of them uses a .dll. And whenever the IExpress package tries to run the first executable it says that the .dll could not be found, even tough I added the .dll inside and outside the package.
There is any way to make it work with IExpress, which has the required characteristics?
There is any alternative to my problem, as a similar software, for instance?

This sounds vaguely similar to this question:
Iexpress is extracting to %temp% folder... How do I prevent this?
As I mentioned in my answer, check: (1) is long file name (LFN) support enabled? and (2) is the .dll actually in the archive?
If checking those things doesn't resolve it, I would use Process Monitor to see which directories the executable is searching to locate the .dll file. It should ideally be looking in the extraction directory (eg %temp%\IXP000.TMP), since that's the current directory when the executable is running.
Of course there are several other utilities that do what IExpress does that you might try instead: 7-Zip, Inno Setup, NSIS, WinRAR, WiX – just to name a few.

Related

How to find difference between the content of .exe and .msi (installer)

I recently took charge of a new system, it is a windows application written in C#, an installer (.MSI) file is created for its distribution. When I install the software it installs properly but it crashes on start. Then if I run the .exe file once for the application, the installed software starts working.
My observation is that .EXE installs some missing bit which is required by .MSI file. Is there a way I can find what files are missing in .MSI file ?
UPDATE on 09-08-2014:
I have found WER4A29.tmp.WERInternalMetadata.xml file which talks about System.Net.WebException
-<ProblemSignatures>
<EventType>CLR20r3</EventType>
<Parameter0>test.exe</Parameter0>
<Parameter1>1.0.3.33</Parameter1>
<Parameter2>53dca4f6</Parameter2>
<Parameter3>System</Parameter3>
<Parameter4>4.0.30319.18408</Parameter4>
<Parameter5>52311185</Parameter5>
<Parameter6>21b0</Parameter6>
<Parameter7>1fb</Parameter7>
<Parameter8>System.Net.WebException</Parameter8>
</ProblemSignatures>
First run an admin install via command line (cmd.exe) to extract the files from your MSI:
msiexec /a File.msi
Then inspect the extracted files to determine if there are configuration EXE files that perform configuration tasks. Determine what configuration files are there, if any. For example INI or XML files. Check for per user / user profile files.
In case you don't have the tool to view the MSI file, get hold of Orca or install a trial version of a commercial packaging tool. You will need this to see what is happening inside the MSI file. If you list the content of the Custom Action table there may be clues there as to what is going on. Also look in the Registry table for per user data to go into the registry. Debugging an MSI properly takes a lot of domain knowledge, but looking through it like this is useful too. Just post follow-up questions. I assume you have the Wix source code too?
To debug the application launch use Process Monitor (procmon.exe) to determine what is going on during the successful launch. The logging is a bit verbose, but with flags you will get to narrow it down.
- For native applications (Win32, or non-.net), I like to use Dependency Walker (depends.exe) too. It can be used for .NET too, but I find it less useful. I am not aware what the best dependency scanner for .NET is at the moment.
If manual debugging fails, several tools used for application repackaging are able to scan the system and determine the state before and after something is done and capture it as a list of differences. Advanced Installer's trial version should be able to do this. With some technical insight you should be able to identify what is needed from the diff image.
The .msi file is the installation set-up it include the installation script and the actual executable .exe file and other required dlls and configuration files.
I think the issue is with how the set-up is created. when you start the application after installation it is not performing the start up tasks like configuration of environment.
And the when you run the .exe it takes care of these configruations by it self.
I suggest that the testing of setup files .msi files and its generation scripts should be revisited.

Why my WPF program cannot run without Visual Studio?

I made a WPF program which uses SQLite. And by using Visual Studio 2012, it generates both Debug and Release version exe file. When I go to Debug or Release directory and run my exe file, e.g. MultiStart.exe, it can run normally.
But if I copy the MultiStart.exe to my Desktop and try to run it, it failed.
By several tests, I found that I also need to copy files MultiStart.exe.config and System.Data.SQLite.dll to my Desktop. And then it can run now.
But why? Do we have better solution so that I can make it run without addition files?
Thanks!
Why my WPF program cannot run without Visual Studio?
The question title is not really accurate since it's not really related Visual Studio. MultiStart.exe is dependent on configuration (MultiStart.exe.config) as well as other assemblies (System.Data.SQLite.dll). Without these dependencies the application cannot run (because that is how .NET works).
WPF doesn't necessarily need a config file to run so the question is what is in your config file that the application needs. It might be possible to move this configuration information into the code (e.g. connection string) and remove the app.config but then the values will be hard coded in the application.
In terms of dependent assemblies, instead of deploying them it is possible to embed them as resources and then use the AppDomain.AssemblyResolve Event to read the assembly from a resource (see Embedding assemblies inside another assembly for an example).
Another approach instead of embedding assemblies as resources is to merge them into one assembly. ILMerge is a popular choice for merging assemblies but I read that it can have issues with WPF assemblies (not sure if that applies to you). See Merging dlls into a single .exe with wpf for some other ideas for merging assemblies with WPF.
Note that setting PATH variables does not work because .NET does not use the PATH for resolving assemblies -- see How the Runtime Locates Assemblies for the details.
Another, option instead of copying the MultiStart.exe to the desktop is to use a shortcut on the desktop that links to the appropriate directory. Perhaps that is a simpler solution
You can also use ILMerge to merge all dependencies into single .exe file to simplify distributiuon of your application.
More detaiils on ILMerge can be found here: ILMerge on CodeProject
Example of usage: ilmerge /target:winexe /out:YourDestinationApp.exe
YourCurrentProgram.exe System.Data.SQLite.dll
Better solution that i used to do with my windows form apps is, Copy the entire folder, which contains supporting files. place it where you want. then create a shortcut of your .exe on your desktop. That always worked for me.
Because you are missing some dependency. You can open your config file and set the dependency...but I wouldn't recommend you to change config file manually.
You can also copy the dependent dll in system32 folder. ..but its only a trick because exe first search dlls in current folder than system 32 folder.
Because you're missing things from your PATH. Visual Studio is probably set to copy DLLs to the target directory on build.
You're almost certainly pulling in external libraries. Some of these are part of .NET, while others are packaged in libraries in specific folders. When you start your exe, it looks in your PATH and the current folder for everything (which includes all DLLs Visual Studio copied).
When you moved the exe to the desktop, suddenly it had no idea where those DLLs are. You haven't specifically added them to your PATH, and they are no longer in the current folder. This is why copying those DLLs to your desktop magically made them work.
Unless you stop use SQLite, there is not a way for you to not need that DLL (there are lots of ways to package/reference it though).

How can I convince mkbundle to include MonoPosixHelper?

I'm using mkbundle and trying to create an embedded version of a little program IdaTester that uses Isis2. That system in turn uses features from Mono that depend on MonoPosixHelper
My problem is that mkbundle doesn't recognize the dependency and I end up with an executable that still needs to dynamically link against ~/bin/lib/libMonoPosixHelper.so, causing problems when I move this executable to a system where I don't have Mono installed. In effect, the bundle is missing one of the things it should be statically linked against.
My executable does work, but only if I make sure to run it only on machines that have the dynamic library in the "right place". This defeats the purpose of an embedded executable... I was hoping to be able to hand people this program as a kind of server they could put anywhere and launch as a binary, and obviously if they need to install the library for this to work, the server isn't exactly standalone!
I see how to force mkbundle to include any dll files the program depends upon, but MonoPosixHelper doesn't exist as a dll; this is a Linux-only library and exists only as a shared library. Does anyone know of a way to "force" the bundle to embed it statically?
In case this helps, my little compile script is as follows:
mcs -debug+ IdaTester.cs Isis.cs -r:System.dll -r:Microsoft.CSharp.dll -r:Mono.Posix.dll
mkbundle --static -o IdaTester IdaTester.exe --deps
I then run IdaTester; this works on platforms where the libMonoPosixHelper library can be found, but will fail at runtime when trying to dynamically load that library if running on a platform where libMonoPosixHelper hasn't been installed...
One needs to distribute libMonoPosixHelper.so with the application and change the dll map to make this work.
Background on the problem - Library is Loaded at Runtime
libMonoPosixHelper is not statically linked but searched for and loaded as a P/Invoke call, such as the example below:
[DllImport ("MonoPosixHelper")]
static extern int zipClose (ZipHandle handle, string globalComment);
That is, it is only requested at runtime, not compile time, and so cannot be linked in ahead of time.
Fixing it - Distributing libMonoPosixHelper.so
Four steps are required.
Copy libMonoPosixHelper to the directory you will be distributing the program with.
Update the DllMap config file to avoid a hard coded location.
Embed the config file with mkbundle
Add the path with libMonoPosixHelper.so to the LD_LIBRARY_PATH on the install machine.
To perform each:
1. Copy libMonoPosixHelper to the directory you will be distributing the program with.
libMonoPosixHelper is usually located in the lib folder, simply copy it to the folder you will be making a tarball out of.
cp $MONO_ROOT/lib/libMonoPosixHelper.so ~/MY_PROGRAM/
2. Update the DllMap config file to avoid a hard coded location.
This is the critical bit to avoid the hard coded paths issue. We need to embed a config file with mkbundle that does not specify the path. To do this, first find the mono config file, and also copy that to the local directory
cp $MONO_ROOT/etc/mono/config ~/MY_PROGRAM/config
Now we need to alter this file to remove the specific path for the dll, open it with your favorite editor and change the paths to avoid the specific prefix:
<dllmap dll="MonoPosixHelper" target="MACHINE_SPECIFIC/lib/libMonoPosixHelper.dylib" os="!windows" />
to
<dllmap dll="MonoPosixHelper" target="libMonoPosixHelper.dylib" os="!windows" />
3. Embed the config file with mkbundle
Add the following option to your mkbundle command to embed the newly edited config file:
--config MY_PROGRAM/config
4. Add the path with libMonoPosixHelper.so to the LD_LIBRARY_PATH on the install machine.
Now you can zip up your mkbundled executable, libMonoPosixHelper.so and any other files for distribution. When unzipped and run on a machine, dlopen will now look for libMonoPosixHelper.so just like any other dll. So simply add whatever directory contains your distributed version of libMonoPosixHelper to their LD_LIBRARY_PATH environmental variable
As far as I can tell, the best option available to me is either to build a non-shared Mono library containing the same methods as are currently found in MonoPosixHelper.so, or to provide a copy of MonoPosixHelper.so as a component to be installed in the same folder as my server. Neither seems ideal: the former forces me to "reach into" the Mono distribution, which creates a longer term maintenance issue, while the latter forces me into a more complex distribution and installation mode. But it seems that once one generates a shared library, you simply can't statically link against that version of the library; the Linux loader just doesn't treat such a thing as a library in the way it handles more standard libraries.
In contrast, if I do generate a standard library from the same .o files, the loader will be happy to statically link against it, and because mxbundle ultimately runs cc and hence uses the standard ld, that option would work for me. So I guess that's the answer to my question.

Possible to package all needed files in an EXE?

I wrote an EXE that uses a third party dll and a template excel document. Anytime someone uses it they have to copy all three files (which is a pain).
Is there any way I can package everything that is needed into the EXE so there is only one file to worry about?
This is something that ilmerge is used for, atleast for combining assemblies. There is more information here and here.
There are several known problems with this though.
Yes - drag it into your project resources (My Project > Resources tab) and from there you can access it using global::Resources.resourceFile (I think - that might not be the right syntax, an alternative is here) as a byte stream and write it locally from there.
You can add files to your project in visual studio and set Build Action to None and Copy to Output directory to Copy always.
or
You can add these files to assembly resources. Adding and Editing Resources (Visual C#)
I suggest doing the first.
Also, for 3rd party dll: set Copy Local to true for the reference.
After you have your project set like this. Create setup project in VS and it will make one exe as you want.
How to: Create or Add a Setup Project
Software installation is a pain, but I think you can get away with an xcopy style deployment by using the compression tool of your choice (like winzip) and creating a self extracting executable.

System.Addin & ClickOnce

I have a annoying build process from using System.Addins API with ClickOnce. Using System.Addins requires a specific directory structure, and the main project does not reference the adapters, view, and contract directly, which doesn't work well with the ClickOnce architechture.
The annoying part with the build process is that I have to copy, via post build event, the .dlls from the add-in components into the directory of the main app project, then reference those files manually from the main project, so that ClickOnce will include them. Firstly, this takes 2 iterations of build to get it to build correctly, secondly, it interferes with source control (I have to exclude the copied add-in dll files from source control or any changes made to them would require checkout).
So, my question is, is there a way around this hack? Something more elegant?
I can't fully answer your question, but it appears you are creating ClickOnce deployments through Visual Studio. I would ditch that method and use MageUI instead. It's a stand-alone executable that can be found in the framework SDK that will generate your application and deployment manifest files. It comes with a gui version (mageui.exe) and a command line version (mage.exe).
Mage may not get rid of your post-build event but it should do away with having to reference the files to get ClickOnce to see them.
Thanks for your input, I am currently doing it the way you mentioned; creating the folder in my project, and include the dlls that I need. It works, but it's an ugly solution, and it interferes with Source Control.
I'm aware of the limitations of ClickOnce, I was hoping there may be a way around it. For example, I read somewhere that I can use deployment projects to create the appropriate dependencies needed in a specific structure. The problem with that is once it is deployed to the public, there is no easy way (within ClickOnce) to update those dependencies.
The solution I use is to have a single output folder for all projects. Every project puts it's own files in the correct subfolder. The application bootstrapper project puts his dlls also in the output (root) folder. When you then create a click-ones for the bootstrapper, it will take all the content from the output folder.
The hardest part is to actually get all the dll's in the right place (and have every dll only once)
I solved this problem by adding the pipeline assemblies as content into the main solution structure.
To do this, change the output folder from (/bin/debug /bin/Release) to something else. I used ../lib otherwise you would get a visual studio cannot reference this file error.
Create the pipeline folders in your main solution
\AddInSideAdapters
\AddInViews
\Contracts
\HostSideAdapters
Right click on each of the folders and click "add existing item" change to view all files and then browse to your ../lib (or wherever you have the output set) and then pull down the add button (click the down arrow) and click "Add as a Link".
Right click on each file and set it to Content.
This will create a refresh file pointed to your assemblies and they will be included into the clickonce manifest.
ClickOnce do not let you install the software where you want. It will install the binary and dlls in the documents and settings. You can in your project properties go in the Publish tab and select Application Files to select additional file to Include. If the System.Addings require dll in a specific folder relatively to your assembly, you might just create the folder in you project and includes from here the dlls. This might works. If not, I do not have "hack" or other solution, clickonce is great but limited with some functionalities.

Categories

Resources