1

I have a problem with an active x component I wrote in C#. Despite I've registered the dll with regasm I'm currently not able to create an active x object...

Here is my code from the class:

using System;
using System.Collections;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Diagnostics;
using System.Security.Policy;
using System.Security;
using Ch.XXX.System6.Modules.Logger;

namespace Gadget.Interop
{
    /// <summary>
    /// GadgetAdapter is the starting point for loading and unloading .NET assemblies
    /// from javascript or any COM-based environment.
    /// </summary>
    [ComVisible(true)]
    [ClassInterface(ClassInterfaceType.None)]
    [Guid("21A72577-3D2D-4664-93F7-1BE02AE68240")]
    [ProgId("GadgetInterop.GadgetAdapter")]
    [ComDefaultInterface(typeof(IGadgetInterop))]
    public class GadgetAdapter : IGadgetInterop, IDisposable, IObjectSafety
    {
        [DllImport("kernel32.dll")]
        static extern IntPtr GetModuleHandle(string module);
        [DllImport("kernel32.dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        static extern bool FreeLibrary(IntPtr handle);
        [DllImport("kernel32.dll")]
        public extern static bool GetModuleHandleExA(int dwFlags, string ModuleName, ref IntPtr phModule);
        [DllImport("kernel32.dll")]
        static extern IntPtr LoadLibrary(string lpFileName);

        /// <summary>
        /// Gadget.Interop.dll Name for FreeLibrary Function
        /// </summary>
        private const string DLLNAME = "Gadget.Interop.dll";

        /// <summary>
        /// Parameters for the constructor
        /// </summary>
        private ArrayList paramList = new ArrayList(); // Array list to  hold constructor parameters

        /// <summary>
        /// Zusätzliche AppDomain
        /// </summary>
        private AppDomain appDomain;


        /// <summary>
        /// Standard Konstruktor
        /// </summary>
        public GadgetAdapter() { }

        #region IGadgetInterop Members
        /// <summary>
        /// Adds an object to be passed to a class' constructor.  Values must be passed to 
        /// this method in the same order of the constructor's arguments.
        /// </summary>
        /// <param name="parameter">Constructor agrument value</param>
        public void AddConstructorParam(object parameter)
        {                
            paramList.Add(parameter);
        }

        /// <summary>
        /// Creates an instance of the specified type.  Constructor parameters are used when
        /// calling this method if they exist, but are forcibly cleared after object creation.
        /// </summary> 
        /// <param name="assemblyFullPath">Full path to and name of the assembly to load</param>
        /// <param name="className">Full namespace and class name of the type to create</param>
        /// <returns>Instance of an object represented by the className arg ument</returns>
        public object LoadType(string assemblyFullPath, string className)
        {
            try
            {
                ILog log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType.Name);

                log.Info("Finally we arrived our C# code");
                return LoadTypeWithParams(assemblyFullPath, className, false);
            }
            catch (Exception ex)
            {
                // Javascript-friendly exception
                throw new Exception("Finally we arrived c# code" + ex.Message);
            }
        }
        /// <summary>
        /// Creates an instance of the specified type. 
        /// <param name="preserveParams">Clears the constructor parameters if false</param>
        /// <returns>Instance of an object represented by the className argument</returns>
        public object LoadTypeWithParams(string assemblyFullPath, string className, bool preserveParams)
        {
            //Load Gadget.Interop.dll over the Gadget.Interop.dll
            LoadLibrary(DLLNAME);

            //Setup extra AppDomain
            AppDomainSetup setup = new AppDomainSetup();
            setup.ApplicationBase = AppDomain.CurrentDomain.BaseDirectory;

            setup = AppDomain.CurrentDomain.SetupInformation;
            setup.PrivateBinPath = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
            setup.PrivateBinPathProbe = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
            setup.ApplicationName = "GadgetAdapter-Loader";
            setup.ShadowCopyFiles = "true";

            appDomain = AppDomain.CreateDomain(
               /*Generate a dynamic name*/
              "GadgetAdapter - Assembly" + Path.GetRandomFileName(), null, setup);

            try
            {
                //Set security
                object[] hostEvidence = { new Zone(SecurityZone.MyComputer) };

                //Create an Evidence based on the Security Zone
                //Evidence intEvidence = new Evidence(hostEvidence, null);

                //Load an assembly in an own application domain
                return (appDomain.CreateInstanceFromAndUnwrap(
                     assemblyFullPath,
                     className, true, BindingFlags.CreateInstance | BindingFlags.Instance | BindingFlags.Public,
                     null, paramList.ToArray(), CultureInfo.CurrentCulture, null));
            }
            catch (Exception ex)
            {
                //Eintrag ins EventLog schreiben
                string sSource;
                string sLog;
                string sEvent;

                sSource = "XXX Sidebar Gadget";
                sLog = "Sidebar Gadget";
                sEvent = "Unhandled Exception in Gadget.Interop.GadgetAdapter";

                //Eventlog Eintrag schreiben
                if (!EventLog.SourceExists(sSource))
                    EventLog.CreateEventSource(sSource, sLog);
                EventLog.WriteEntry(sSource, sEvent + Environment.NewLine + ex.Message + Environment.NewLine + ex.InnerException,
                    EventLogEntryType.Error);

                throw new Exception(ex.InnerException.ToString());
            }
        }

        /// <summary>
        /// Call the object's Dispose method and sets the object to null;
        /// </summary>
        /// <param name="typeToUnload">Type implementing IDisposable to be destroyed</param>
        public void UnloadType(object typeToUnload)
        {
            try
            {
                //Verfiy Unloadtype
                if (typeToUnload != null && typeToUnload is IDisposable)
                {
                    //Dispose
                    (typeToUnload as IDisposable).Dispose();

                    if (appDomain != null)
                    {
                        //Unload ApplicationDomain
                        AppDomain.Unload(appDomain);
                        appDomain = null;
                    }
                }

                //Set instance to null
                typeToUnload = null;                
            } 
            catch (Exception exception)
            {
                //Eintrag ins Eventlog schreiben
                string sSource;
                string sLog;
                string sEvent;

                sSource = "XXX Sidebar Gadget";
                sLog = "Sidebar Gadget";
                sEvent = "Unhandled Exception in Gadget.Interop.GadgetAdapter";

                //Eventlog Eintrag schreiben
                if (!EventLog.SourceExists(sSource))
                    EventLog.CreateEventSource(sSource, sLog);
                EventLog.WriteEntry(sSource, sEvent + Environment.NewLine + exception.Message + Environment.NewLine + exception.InnerException,
                    EventLogEntryType.Error);
            } 
        }

        #endregion

        #region IDisposable Members 

        /// <summary>
        /// Dispose Methode for the GadgetAdapter
        /// </summary>
        public void Dispose()
        {
            //Clear constructor parameters
            this.paramList.Clear();
            paramList = null;

            try
            {
                //Unload the GadgetAdapter over Kernel32 functions
                IntPtr hMod = IntPtr.Zero;
                if (GetModuleHandleExA(0, DLLNAME, ref hMod))
                {
                    bool s = false;
                    do
                    {
                        s = FreeLibrary(hMod);
                    } while (s);
                }
            }
            finally
            {
                GC.SuppressFinalize(this);
            }

        }

        #region IObjectSafety Members
        public enum ObjectSafetyOptions
        {
            INTERFACESAFE_FOR_UNTRUSTED_CALLER = 0x00000001,
            INTERFACESAFE_FOR_UNTRUSTED_DATA = 0x00000002,
            INTERFACE_USES_DISPEX = 0x00000004,
            INTERFACE_USES_SECURITY_MANAGER = 0x00000008
        };

        public int GetInterfaceSafetyOptions(ref Guid riid, out int pdwSupportedOptions, out int pdwEnabledOptions)
        {
            ObjectSafetyOptions m_options = ObjectSafetyOptions.INTERFACESAFE_FOR_UNTRUSTED_CALLER | ObjectSafetyOptions.INTERFACESAFE_FOR_UNTRUSTED_DATA;
            pdwSupportedOptions = (int)m_options;
            pdwEnabledOptions = (int)m_options;
            return 0;
        }
        public int SetInterfaceSafetyOptions(ref Guid riid, int dwOptionSetMask, int dwEnabledOptions)
        {
            return 0;
        }
        #endregion

        #endregion
    }
}

And here is the interface:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;

namespace Gadget.Interop
{
    /// <summary>
    /// Interface required COM registration.  This interface outlines methods
    /// used to create and destroy managed .NET types
    /// </summary>
    [ComVisible(true)]
    [InterfaceType(ComInterfaceType.InterfaceIsDual)]
    [Guid("618ACBAF-B4BC-4165-8689-A0B7D7115B05")]
    public interface IGadgetInterop
    {
        object LoadType(string assemblyFullPath, string className);
        object LoadTypeWithParams(string assemblyFullPath, string className, bool preserveParams);
        void AddConstructorParam(object parameter);
        void UnloadType(object typeToUnload);
    }
}

When I try a simple CreateObject in a vb script

Set wshShell2 = CreateObject("GadgetInterop.GadgetAdapter")

I also tried:

Set wshShell2 = CreateObject("Gadget.Interop.GadgetAdapter")

I get the error: 800A01AD ActiveX component can not create an object

Anybody else had the same problem?

EDIT: I also see the component in the ole viewer...

Thanks

yms
  • 10,361
  • 3
  • 38
  • 68
user886091
  • 25
  • 3
  • 7
  • Did you run `regasm` with the `/verbose` option to see if it actually registers something? Did you specify `/tlb`? You could also try to use OLE viewer to see if the registration was successful. – Andre Feb 29 '12 at 14:41
  • Hi Andre, thanks for your response. I tried to run regasm with the /verbose and I also specified /tlb.. Nothing changed, still not able to create an object.... I see the component in the ole viewer – user886091 Feb 29 '12 at 15:08
  • maybe you are building the component as 32bits and trying to use it from the 64 bit vbscript interpreter? Try using c:\windows\syswow64\wscript.exe to run your script. – yms Feb 29 '12 at 16:22
  • That's it!! With the 64bit wscript.exe it works!! I have javascript which creates an object from this active x component.. This javascript is for a windows sidebar gadget... What can I do there to be sure it works on a 32bit and on a 64bit machine as well? Greets Marco – user886091 Feb 29 '12 at 17:07

1 Answers1

2

64 bit COM objects cannot be used directly from 32 bits applications and vice versa. In this scenario, you should specify your .net-based COM object as AnyCPU, and register it for both CPU architectures as specified in this SO answer. Basically, you need to run REGASM in

C:\Windows\Microsoft.NET\Framework\v2.0.50727>

and

C:\Windows\Microsoft.NET\Framework64\v2.0.50727>

Community
  • 1
  • 1
yms
  • 10,361
  • 3
  • 38
  • 68