My boss has asked if there's any way that the whole thing can be
delivered as a single stand-alone executable rather than write an
installer.
I've said that I don't believe it is, but that I'd ask in here to make
certain.
Fairly simply, in fact...
So, is it possible to include an ActiveX DLL in a C# app so that the user
doesn't need to register it directly? I understand about embedding
binaries and then extracting them at runtime - is that a possible
solution?
Yep - code below. However, I should point out that I don't consider this a
particularly elegant, robust or desirable solution, but nevertheless it's
easy enough to do... The only problem you will have is that as soon as
your app makes its first call to the ActiveX DLL, it will "hook" it, so
you're unlikely to be able to unregister it and delete it as your app
closes which will mean that you'll have to delete it manually... Your
suggestion to use an installer is by far the better option...
Also, note that you will need to include the InterOp wrapper which your
app will create when it compiles...
Also, I understand that a .NET assembly can be given a COM wrapper - is
the reverse possible? I.e. can a COM object be wrapped in a .NET
assembly?
Not as far as I know... Having said that, the VC++ code for DSOFile.dll is
readily available for download from the Microsoft website, so you could
have a bash at turning it into a native .NET assembly - I'm not nearly
skilled enough in VC++ to even attempt that...
// in your app's startup ------------------------
Stream objStream = null;
BinaryReader objBinaryReader = null;
FileStream objFileStream = null;
BinaryWriter objBinaryWriter = null;
byte[] abytBytes;
try
{
// extract the
DLL --------------------------------------------------------------------------
objStream =
Assembly.GetExecutingAssembly().GetManifestResourceStream("<MyAssemblyName>.dsofile.dll");
objBinaryReader = new BinaryReader(objStream);
objFileStream = new
FileStream(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)
+ "\\dsofile.dll", FileMode.Create);
objBinaryWriter = new BinaryWriter(objFileStream);
abytBytes = new byte[objStream.Length];
objStream.Read(abytBytes, 0, abytBytes.Length);
objBinaryWriter.Write(abytBytes);
objBinaryReader.Close();
objBinaryWriter.Close();
// register the
DLL ----------------------------------------------------------------
using (Process objProcess = new Process())
{
objProcess.StartInfo.UseShellExecute = false;
objProcess.StartInfo.RedirectStandardOutput = false;
objProcess.StartInfo.RedirectStandardError = false;
objProcess.StartInfo.CreateNoWindow = true;
objProcess.StartInfo.FileName = "regsvr32.exe";
objProcess.StartInfo.Arguments = "dsofile.dll /s";
objProcess.Start();
objProcess.WaitForExit();
}
// extract the type
library -----------------------------------------------------------------
objStream =
Assembly.GetExecutingAssembly().GetManifestResourceStream("<MyAssemblyName>.Interop.DSOFile.dll");
objBinaryReader = new BinaryReader(objStream);
objFileStream = new
FileStream(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)
+ "\\Interop.DSOFile.dll", FileMode.Create);
objBinaryWriter = new BinaryWriter(objFileStream);
abytBytes = new byte[objStream.Length];
objStream.Read(abytBytes, 0, abytBytes.Length);
objBinaryWriter.Write(abytBytes);
objBinaryReader.Close();
objBinaryWriter.Close();
#endif
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK,
MessageBoxIcon.Error);
}
finally
{
if (objBinaryWriter != null)
{
objBinaryWriter.Close();
objBinaryWriter = null;
}
if (objFileStream != null)
{
objFileStream.Close();
objFileStream.Dispose();
}
if (objBinaryReader != null)
{
objBinaryReader.Close();
objBinaryReader = null;
}
if (objStream != null)
{
objStream.Close();
objStream.Dispose();
}
}
// in your app's exit routine -------------
try
{
using (Process objProcess = new Process())
{
objProcess.StartInfo.UseShellExecute = true;
objProcess.StartInfo.RedirectStandardOutput = false;
objProcess.StartInfo.RedirectStandardError = false;
objProcess.StartInfo.CreateNoWindow = true;
objProcess.StartInfo.FileName = "regsvr32.exe";
objProcess.StartInfo.Arguments = "dsofile.dll /u /s";
objProcess.Start();
objProcess.WaitForExit();
}
File.Delete(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)
+ "\\dsofile.dll");
File.Delete(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)
+ "\\Interop.DSOFile.dll");
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK,
MessageBoxIcon.Error);
}