I have a Windows C# program that uses a C++ dll for data i/o. My goal is to deploy the application as a single EXE.
What are the steps to create such an executable
Smart Assembly can do this and more. If your dll has unmanaged code, it wont let you merge the dlls to a single assembly, instead it can embed the required dependencies as resources to your main exe. Its flip-side, its not free.
You can do this manually by embedding dll to your resources and then relying on AppDomain's Assembly ResolveHandler
. When it comes to mixed mode dlls, I found many of the variants and flavours of ResolveHandler
approach to not work for me (all which read dll bytes to memory and read from it). They all worked for managed dlls. Here is what worked for me:
static void Main()
{
AppDomain.CurrentDomain.AssemblyResolve += (sender, args) =>
{
string assemblyName = new AssemblyName(args.Name).Name;
if (assemblyName.EndsWith(".resources"))
return null;
string dllName = assemblyName + ".dll";
string dllFullPath = Path.Combine(GetMyApplicationSpecificPath(), dllName);
using (Stream s = Assembly.GetEntryAssembly().GetManifestResourceStream(typeof(Program).Namespace + ".Resources." + dllName))
{
byte[] data = new byte[stream.Length];
s.Read(data, 0, data.Length);
//or just byte[] data = new BinaryReader(s).ReadBytes((int)s.Length);
File.WriteAllBytes(dllFullPath, data);
}
return Assembly.LoadFrom(dllFullPath);
};
}
The key here is to write the bytes to a file and load from its location. To avoid chicken and egg problem, you have to ensure you declare the handler before accessing assembly and that you do not access the assembly members (or instantiate anything that has to deal with the assembly) inside the loading (assembly resolving) part. Also take care to ensure GetMyApplicationSpecificPath()
is not any temp directory since temp files could be attempted to get erased by other programs or by yourself (not that it will get deleted while your program is accessing the dll, but at least its a nuisance. AppData is good location). Also note that you have to write the bytes each time, you cant load from location just 'cos the dll already resides there.
If the assembly is fully unmanaged, you can see this link or this as to how to load such dlls.
PostBuild from Xenocode can package up both managed and unmanged into a single exe.