0
votes

I Have an activex control project in c# which references a dll file that I built myself.

Now I click a button and I see it failing with this exception:

System.IO.FileNotFoundException: Could not load file or assembly 'MtnLib, Version=1.0.0.0, Culture=neutral, PublicKeyToken=111045ceeaeac3e4' or one of its dependencies. The system cannot find the file specified. File name: 'MtnLib, Version=1.0.0.0, Culture=neutral, PublicKeyToken=111045ceeaeac3e4'
at CSActiveX.MtnControl.button1_Click(Object sender, EventArgs e)
at System.Windows.Forms.Control.OnClick(EventArgs e) at System.Windows.Forms.Button.OnClick(EventArgs e) at System.Windows.Forms.Button.OnMouseUp(MouseEventArgs mevent) at System.Windows.Forms.Control.WmMouseUp(Message& m, MouseButtons button, Int32 clicks) at System.Windows.Forms.Control.WndProc(Message& m) at System.Windows.Forms.ButtonBase.WndProc(Message& m) at System.Windows.Forms.Button.WndProc(Message& m) at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m) at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m) at System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)

I've enabled log and these are the logs:

LOG: DisplayName = MtnLib, Version=1.0.0.0, Culture=neutral, PublicKeyToken=111045ceeaeac3e4 (Fully-specified) LOG: Appbase = file:///C:/Program Files (x86)/Internet Explorer/ LOG: Initial PrivatePath = NULL Calling assembly : CSActiveX, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null. === LOG: This bind starts in LoadFrom load context. WRN: Native image will not be probed in LoadFrom context. Native image will only be probed in default load context, like with Assembly.Load(). LOG: No application configuration file found. LOG: Using host configuration file: LOG: Using machine configuration file from C:\Windows\Microsoft.NET\Framework\v4.0.30319\config\machine.config. LOG: Post-policy reference: MtnLib, Version=1.0.0.0, Culture=neutral, PublicKeyToken=111045ceeaeac3e4 LOG: Attempting download of new URL file:///C:/Program Files (x86)/Internet Explorer/MtnLib.DLL. LOG: Attempting download of new URL file:///C:/Program Files (x86)/Internet Explorer/MtnLib/MtnLib.DLL. LOG: Attempting download of new URL file:///C:/Program Files (x86)/Internet Explorer/MtnLib.EXE. LOG: Attempting download of new URL file:///C:/Program Files (x86)/Internet Explorer/MtnLib/MtnLib.EXE. LOG: Attempting download of new URL file:///C:/temp/MtnControl/Debug/MtnLib.DLL. LOG: Attempting download of new URL file:///C:/temp/MtnControl/Debug/MtnLib/MtnLib.DLL. LOG: Attempting download of new URL file:///C:/temp/MtnControl/Debug/MtnLib.EXE. LOG: Attempting download of new URL file:///C:/temp/MtnControl/Debug/MtnLib/MtnLib.EXE.

My project references MtnLib.dll and I do see the file under C:\temp\MtnControl\Debug\MtnLib.dll So I don't understand why IE isn't finding the file.

this is my control:

using System;
using System.ComponentModel;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using MtnLib;    

namespace CSActiveX
{
    #region Interfaces

    /// <summary>
    /// AxCSActiveXCtrl describes the COM interface of the coclass 
    /// </summary>
    [Guid("D4B8539E-3839-3913-8B1A-C551A9930864")]
    public interface AxCSActiveXCtrl
    {
        #region Properties

        bool Visible { get; set; }          // Typical control property
        bool Enabled { get; set; }          // Typical control property
        #endregion

        #region Methods
        void Refresh();
        #endregion
    }

    #endregion

    [ClassInterface(ClassInterfaceType.None)]        
    [Guid("80B59B58-98EA-303C-BE83-D26E5D8D6794")]
    public partial class MtnControl : UserControl, AxCSActiveXCtrl
    {
        #region ActiveX Control Registration

        // These routines perform the additional COM registration needed by 
        // ActiveX controls

        [EditorBrowsable(EditorBrowsableState.Never)]
        [ComRegisterFunction()]
        public static void Register(Type t)
        {
            try
            {
                ActiveXCtrlHelper.RegasmRegisterControl(t);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message); // Log the error
                throw;  // Re-throw the exception
            }
        }

        [EditorBrowsable(EditorBrowsableState.Never)]
        [ComUnregisterFunction()]
        public static void Unregister(Type t)
        {
            try
            {
                ActiveXCtrlHelper.RegasmUnregisterControl(t);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message); // Log the error
                throw; // Re-throw the exception
            }
        }


        #endregion           

        private void button1_Click(object sender, EventArgs e)
        {
            //call a function from MtnLib
        }
    }

} // namespace CSActiveX

this is my ActiveXCtrlHelper:

[ComVisible(false)]
internal class ActiveXCtrlHelper : AxHost
{
    internal ActiveXCtrlHelper()
        : base(null)
    {
    }

    #region ActiveX Control Registration

    #region OLEMISC Enumeration

    // Ref: http://msdn.microsoft.com/en-us/library/ms678497.aspx
    const int OLEMISC_RECOMPOSEONRESIZE     = 1;
    const int OLEMISC_CANTLINKINSIDE        = 16;
    const int OLEMISC_INSIDEOUT             = 128;
    const int OLEMISC_ACTIVATEWHENVISIBLE   = 256;
    const int OLEMISC_SETCLIENTSITEFIRST    = 131072;

    #endregion

    /// <summary>
    /// Register the control as an ActiveX control.
    /// </summary>
    /// <param name="t"></param>
    public static void RegasmRegisterControl(Type t)
    {
        // Check the argument
        GuardNullType(t, "t");
        GuardTypeIsControl(t);

        // Open the CLSID key of the control
        using (RegistryKey keyCLSID = Registry.ClassesRoot.OpenSubKey(
            @"CLSID\" + t.GUID.ToString("B"), /*writable*/true))
        {
            RegistryKey subkey = null;

            // Set "InprocServer32" to register a 32-bit in-process server.
            // InprocServer32 = <path to 32-bit inproc server>
            // Ref: http://msdn.microsoft.com/en-us/library/ms683844.aspx

            subkey = keyCLSID.OpenSubKey("InprocServer32", /*writable*/true);
            if (subkey != null) 
                // .NET runtime engine (mscoree.dll) for .NET assemblies
                subkey.SetValue(null, Environment.SystemDirectory + @"\mscoree.dll");


            // Create "Control" to identify it as an ActiveX Control.
            // Ref: http://msdn.microsoft.com/en-us/library/ms680056.aspx

            using (subkey = keyCLSID.CreateSubKey("Control")) { };


            // Create "MiscStatus" to specify how to create/display an object. 
            // MiscStatus = <combination of values from OLEMISC enumeration>
            // Ref: http://msdn.microsoft.com/en-us/library/ms683733.aspx

            using (subkey = keyCLSID.CreateSubKey("MiscStatus"))
            {
                int nMiscStatus = OLEMISC_RECOMPOSEONRESIZE +
                    OLEMISC_CANTLINKINSIDE + OLEMISC_INSIDEOUT +
                    OLEMISC_ACTIVATEWHENVISIBLE + OLEMISC_SETCLIENTSITEFIRST;

                subkey.SetValue("", nMiscStatus.ToString(), RegistryValueKind.String);
            }


            // Create "ToolBoxBitmap32" to identify the module name and the resource  
            // ID for a 16 x 16 bitmap as the toolbar button face.
            // ToolBoxBitmap32 = <filename>.<ext>, <resourceID>
            // Ref: http://msdn.microsoft.com/en-us/library/ms687316.aspx

            using (subkey = keyCLSID.CreateSubKey("ToolBoxBitmap32"))
            {
                // If you want different icons for each control in the assembly you 
                // can modify this section to specify a different icon each time. 
                // Each specified icon must be embedded as a win32 resource in the 
                // assembly; the default one is at the index 101, but you can use 
                // additional ones.
                subkey.SetValue("", Assembly.GetExecutingAssembly().Location + ", 101",
                    RegistryValueKind.String);
            }


            // Create "TypeLib" to specify the typelib GUID associated with the class. 

            using (subkey = keyCLSID.CreateSubKey("TypeLib"))
            {
                Guid libId = Marshal.GetTypeLibGuidForAssembly(t.Assembly);
                subkey.SetValue("", libId.ToString("B"), RegistryValueKind.String);
            }


            // Create "Version" to specify the version of the control. 
            // Ref: http://msdn.microsoft.com/en-us/library/ms686568.aspx

            using (subkey = keyCLSID.CreateSubKey("Version"))
            {
                int nMajor, nMinor;
                Marshal.GetTypeLibVersionForAssembly(t.Assembly, out nMajor, out nMinor);
                subkey.SetValue("", String.Format("{0}.{1}", nMajor, nMinor));
            }

        }
    }

    /// <summary>
    /// Unregister the control.
    /// </summary>
    /// <param name="t"></param>
    public static void RegasmUnregisterControl(Type t)
    {
        // Check the argument
        GuardNullType(t, "t");
        GuardTypeIsControl(t);

        // Delete the CLSID key of the control
        Registry.ClassesRoot.DeleteSubKeyTree(@"CLSID\" + t.GUID.ToString("B"));
    }

    private static void GuardNullType(Type t, String param)
    {
        if (t == null)
        {
            throw new ArgumentException("The CLR type must be specified.", param);
        }
    }

    private static void GuardTypeIsControl(Type t)
    {
        if (!typeof(Control).IsAssignableFrom(t))
        {
            throw new ArgumentException(
                "Type argument must be a Windows Forms control.");
        }
    }
}

I've checked Register for COM Interop in visual studio and my control is displaying correctly, just the MtnLib.dll cannot be found.

By the way I'm using IE 8 in windows 7 64 bit.

1

1 Answers

0
votes

I turns out that I was testing the control using the 32 bit IE when MtnLib was an x64 library.