Accessing embedded resources in Wix DTF Custom Action - wix

My DTF project contains some embedded resources and I would like to access the same in the CustomAction.
I tried the following code in the Custom Action method
// Gets the current assembly.
Assembly Asm = Assembly.GetExecutingAssembly();
// Resources are named using a fully qualified name.
Stream strm = Asm.GetManifestResourceStream(Asm.GetName().Name + "." + Name);
However this doesnt work as Asm always refers to the Wix Setup assembly and not the custom action dll which contains the resources

Why not use Assembly.GetAssembly(typeof(CustomAction));, to get the assembly that contains your custom action?

To be honest, I'm not sure this scenario is possible. I mean, there might be no option (or no easy option) to get the custom action executing assembly and extract the resources out of it.
Instead of this, I would try to re-design the solution and move resources to the Binary table in MSI package. Thus, you'll still have embedded resources, but not in CA DLL, but in the MSI package itself. The DTF.chm help file contains a sample how to extract files from Binary table - it's a matter of a couple of lines of code.

Related

DTF is copying custom action dll files

I have msi setup that was created in installshield and I am executing the DTF custom action dll as a commit custom action. If I insert MessageBox.Show into the custom action, I can see that there is a temporary folder inside [PROGRAMFILESDIR] called "CustomActionProject.CA.dll-" and there is copied CustomActionProject.CA.dll with all its references.
Is there any way to tell the technology not to create this temp folder and extract+execute the CustomActionProject.CA.dll in the same folder where is .CA.dll located?
Edit:
I found out that I can not include the references in .CA.dll by configuring wix.ca.targets. Which prevents .CA.dll to contain 20MB of dlls in my case.
Now I would like to make sure that CustomActionProject.dll will be able to see the references that are installed with the product.
The files are:
<ProgramFilesFolder>
<MyApplicationFolder>
CustomActionProject.CA.dll
... About 30 dlls installed with the application that CustomActionProject.dll needs to call
<Place I Would Like to See CustomActionProject.dll extracted>
DTF automatically extracts it's files to a temp folder for execution and then cleans up on disposal. This is very good in that it eliminates certain race conditions. You can still author those files into your installer if you like. For example, at a previous company, our installer used several DLL's for license checking during the install and installed them for use by the application at runtime.
BTW, make sure you've seen this:
WiX DTF Behavior Alert
Your custom action was programmed in a managed .Net language (probably C# or VB.Net). As msi files may only contain dll custom actions comprised of native code the DTF tools, specifically the tool makesfxca.exe, packs / wraps the managed dll together with helper code resulting in a self extracting, native code dll. Following WIX´s naming convention the native custom action dll contains an .CA infix.
In order for this (i.e. having custom actions written in languages producing managed code) to work, self extraction has to take place. So the short answer to your question is "No".

MVC - Application Assembly

Question:
If I have multiple projects in one solution is it still considered a single assembly?
Background Information:
I'm aware the 'MyApplication/Properties/AssemblyInfo.cs' file exists. Further, I confirmed that when I:
Add a project to the solution.
Appropriately reference the newly added project.
Lastly, Build the solution.
The 'MyApplication/Properties/AssemblyInfo.cs' file has not changed. This leaves me to believe, and please correct me if I'm wrong that I'll have met the demand.
Thank you
No.
Each project is compiled into one assembly in your case. The assemblyinfo.cs file (for each project) should not change at all when you compile anything. Also, that file's name is not important at all; it's the global attributes inside it that cause various properties of the assembly being created to be set. That file's name and location are simply a convention.

Installshield use a custom dll from another custom dll

I am refactoring an old installshield application and I need to perform a action that calls a function from a custom dll. Unfortunately the function that this action performs depends on another custom dll. So my question is:"Is it possible to have a custom dll depend on another custom dll and if so how?"
When I try to run the installer it crashes with the error "Setup was interrupted before being complete..." Then I copied the second custom dll to a folder that I added to PATH and everything went fine. Of course I can not expect my customer to do that by hand.
I am using Installshield 2008 but I believe the answer to my question will be the same for all versions.
EDIT: as maybe my question is not clear enough I will give example:
Let's say I have a.dll that has a function:
UINT __stdcall
PerformAction(MSIHANDLE hInstall) // IN
{
...
help();
...
}
help() is defined in b.dll. Now when I create a new action I set it's dll to be a.dll and it's function name to be PerformAction but there is no way to indicate this depends on b.dll
When I copy b.dll to a folder included to PATH the installer works ok but if I don't it fails.
The easiest InstallShield approach here is to use support files instead of or in addition to binary table entries. Windows Installer will only extract a single DLL for a custom action, but if you reference a file in SUPPORTDIR, it can use more than one.

Assembly referenced in SSIS 2008 script task not working correctly

I have reference a custom assembly in an ssis script task. The script task apparently works correctly but the assembly (first tested with a console program) doesn't work anymore.
The assembly is supposed to transform a text file to a csv file for further import. Once loaded in the script task the function referenced does create an empty file. Logging did not bring any addtionnal info.
Currently the assembly is strongly named, signed, in the GAC as well as in the DTS\SDK folder of MSSQL server.
Any idea ?
Actually the error was in my own assembly. So to summarize the correct and easy way to include and use an assembly file in a ssis script task is :
Compile the assembly with the correct framework version (in my case 3.5)
Sign the assembly
Put the assembly in the GAC
Reference the assembly within the script task and add an "imports" directive
Actually putting the assembly in the DTS\bin folder did not produce any difference.
This is why I don't usually like using custom assemblies in SSIS. In this case, I would write a jig (exe) to call the assembly and change SSIS to call my exe. In the jig (exe) I would wrap the call to the assembly in a try/catch block. I would trace the incoming parameters and log any errors to a text file or to the system Event Log. Usually, this approach gives me enough insight into the real problem (bad param, permission problem, weird data, etc) and a good way to recreate the problem and verify a solution.

add custom DLL search path # application startup

I'm racking my brain trying to come up with an elegant solution to a DLL load problem. I have an application that statically links to other lib files which load DLLs. I'm not loading the DLLs directly. I'd like to have some DLLs in another folder other than the folder that the executable is in. Something like %working_folder%\dlls - I'd rather not have dozens (yes ... dozens) of DLLs in my %working_folder%.
I'm trying to develop something that is part of the main app that will adjust the search path # startup. The problem I'm running into is that this new custom DLL path isn't in the system search path. When I start the app it crashes (STATUS_DLL_NOT_FOUND) because the necessary DLLs are not in the appropriate places. What I'd like to do is to check # startup if this new custom DLL folder is in the process environment variable search path and if not add it. Problem is, the application attempts to load all these DLLs before the app executes one line of code.
How do I fix this? I've considered writing a help app that starts first, adjusts the environment variables appropriately and the launches the main app via CreateProcess. This will work I'm sure of it but it makes things difficult on the developers. When they debug the main app they're not going to launch a helper app first - not that they could even do that.
I've tried the registry app path feature with no success. Same chicken and egg problem as before.
What can I do here?
I found Matthew's answer worked for me.
In visual studio 2012 goto your project properties and in
Configuration Properties->Linker->Input->Delay Loaded Dlls
add each dll file that you want to not load until needed.
Although it no longer needs to run before main, this is my code to set the new search path
class RunBeforeMain
{
public:
RunBeforeMain()
{
const TCHAR* dllPathEnvName= name of env variable to directory containing dlls
const TCHAR* pathEnvName= TEXT("Path");
TCHAR newSearchPath[4096];
::GetEnvironmentVariable(dllPathEnvName, newSearchPath, MAX_PATH);
//append bin
_tcscat_s(newSearchPath, MAX_PATH, TEXT("bin;"));
size_t length = _tcslen(newSearchPath);
//append existing Path
::GetEnvironmentVariable(pathEnvName, newSearchPath + length, 4096-length);
::SetEnvironmentVariable(pathEnvName, newSearchPath);
}
};
static RunBeforeMain runBeforeMain; //constructor code will run before main.
[Edit - after re-reading the question I see that the problem you're having is that the DLLs are getting loaded before main starts]
I'm guessing that those libraries are written in C++ and are loading the DLLs from the constructor of some objects in global scope. This is problematic. Allow me to quote Yossi Kreinin:
Do it first thing in main(). If you use C++, you should do it first thing before main(), because people can use FP in constructors of global variables. This can be achieved by figuring out the compiler-specific translation unit initialization order, compiling your own C/C++ start-up library, overriding the entry point of a compiled start-up library using stuff like LD_PRELOAD, overwriting it in a statically linked program right there in the binary image, having a coding convention forcing to call FloatingPointSingleton::instance() before using FP, or shooting the people who like to do things before main(). It’s a trade-off.
[Original answer below]
See this page for the search algorithm used for loading DLLs. You can use SetDllDirectory() to add a directory to the DLL search path.
You also should be able to add a directory to the PATH environment variable using GetEnvironmentVariable() and SetEnvironmentVariable().
Another option is to change the current working directory to the folder containing the DLLs with SetCurrentDirectory(). Just make sure to change the working directory back after loading the DLLs if you ever load any files using relative filenames.
My recommendation is to use delayload linking for the DLLs and call SetDllDirectory() early enough so it can find them when the methods/functions are invoked.