人已经焦了...关于C# 创建ActiveX控件

大狗狗 2018-01-12 12:12:10
我从来都不怕不会,也从来不怕不行。我怕的是过去行而现在不行。最近一个多月一直在做一个C# ActiveX控件,就快好了,突生惊天巨变!

为了最终完善这个控件,我今天添加了两个方法,但是在IE中测试时,却提示找不到函数。只有以前那些老方法可用,新增的不能用。我编译、注册都通过了(弄了一个多月,都轻车熟路了),但IE中死活就是说找不到函数。我猜想可能是旧的注册信息无法清除干净。。系统一直在使用我旧版的控件。由于项目紧张,顾不得太多,重新制定了GUID,类名改了,连密钥也改了。我想这等于重新做了个ActiveX控件,系统不会再和旧版混了吧?结果出了更大麻烦,那就是编译能成功,但最后VS注册COM这下总是提示无权限,无法访问注册表相关项。虽然我一直用的最高权限帐号,也完全关闭了UAC,毫无作用。

还有一个发现,就是debug下的tlb文件居然一直没有新版!只有我一个多月前初建项目时那个最老的tlb,后来这家伙就再没更新过!!

现在情况是,我把编译后的DLL用regasm注册,再添加到全局程序集缓冲。IE中使用这个控件,控件的界面是能出来的,但是所有的方法(JS中调用activeX方法)一个也不管用,IE统统提示无函数!

我知道这是一个非常麻烦的问题,如果哪位朋友能帮忙解决,愿意红包酬谢!我扣妖八丝尔路山尔零山
...全文
527 16 打赏 收藏 转发到动态 举报
写回复
用AI写文章
16 条回复
切换为时间正序
请发表友善的回复…
发表回复
大狗狗 2018-01-12
  • 打赏
  • 举报
回复
特别感谢daixf_csdn贴的代码,非常详细。我的解决方案中单独有个安装项目,用户运行我安装包安装注册activeX(类似安装桌面软件那样的,不是cab)能否留个联系方式,我把红包送出。
大狗狗 2018-01-12
  • 打赏
  • 举报
回复
非常感谢回贴的朋友!最终真相大白: 首先呢,VS爆出无权限注册程序集问题还是原因不明,不过无关紧要,因为可以自己手动注册。 先前的项目现在也能顺利运行了,其实GUID名称并不是主要原因,问题的根本原因是: public void setCaption(string value) { control.title = value;//问题就出在这里,此时的control还未被赋值!它是个空引用! } 这样就能解释为什么控件能够显示在网页中,但一调用方法就爆异常(只是这个异常爆的让人想不到,.net 控件没爆异常,JS爆了个找不到函数....) 改了此处bug外,一切正常了。
大狗狗 2018-01-12
  • 打赏
  • 举报
回复
看来红包要被我自己拿到了。经过一翻折腾,现在终于有了进展。虽然原理还是没大弄明白(也没人教啊),不过总算是能顺利导出方法了,操作步骤如下: 1 新建一个项目(原先那个已经烂掉了,越改可能问题越多),把新项目做成一个最简单的activeX,就是不实现具体功能,只包含空方法(里面可加个MessageBox用于验证)。编译试验下,这里极有可能还会爆出该死的无注册权限异常,不要理会,因为只要代码正确,DLL会生成。接下来我们自己注册: 先把DLL copy到system32,然后cmd切到system32执行:(详细可看我blog中文章) gacutil /i myname.dll regasm myname.dll 注册成功,在html代码里建一个object,引用项目GUID,试验成功,OK,现在我们已经有了通往成功的种子。(这说明我们的代码结构是正确的,我们的系统是尚可一用的) 2把代码从原项目中慢慢往新项目中copy,先移那些通用性强的代码( 藕合度小),移一部分就编译下,编译成功再移下一部分。 3在方法中添加功能代码。 注意事项:如果更改了输出方法,比如添加方法,修改方法名,那么修改你ActiveX类的命名空间,修改ActiveX类的GUID。 就这些经验吧,欢迎补充
圣殿骑士18 2018-01-12
  • 打赏
  • 举报
回复
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows.Forms;
using System.Threading;
using Newtonsoft.Json;
using BL.Core;
using BL.Core.WF;
using BL.Device.RfReader;
using System.Reflection;
using System.IO;
using System.Diagnostics;
using Microsoft.Win32;

namespace BL.Device.RfReader.ActiveX
{
    [Guid("2079D3B4-6C55-4F47-876F-DBB874A4F68A")]
    public partial class RfidActiveX : UserControl, IObjectSafety
    {
        private IRFReader reader;
        private List<TagInfo> listTag;     //记录读取到的标签集合
        private ExceptionService exService;
        private string lastError;   //存储错误消息

        /// <summary>
        /// 构造方法
        /// </summary>
        public RfidActiveX()
        {
            InitializeComponent();
        }

        /// <summary>
        /// 控件数据初始化
        /// </summary>
        /// <returns></returns>
        public int Initial()
        {
            listTag = new List<TagInfo>();
            reader = RfReaderFactory.GetReader(ReaderType.R_Cethik_Smart);

            if (reader == null)
            {
                lastError = "不支持的读写器类型!";
                return -1;
            }

            reader.TagsReport += reader_TagsReport;

            return 1;
        }

        /// <summary>
        /// 连接读写器
        /// </summary>
        /// <returns></returns>
        public int Connect()
        {
            if (reader == null)
            {
                lastError = "请先选择读写器!";
                return -1;
            }

            int result = exService.ThreadExceptionCatch(() =>
            {
                reader.Connect();

                btnConnect.Enabled = false;
                btnStart.Enabled = true;

                ConvertEnable();
            });

            if (result == -1) return -1;

            return 1;
        }

        /// <summary>
        /// 断开连接
        /// </summary>
        /// <returns></returns>
        public int DisConnect()
        {
            if (reader == null) return -1;

            int result = exService.ThreadExceptionCatch(() =>
            {
                if (btnStop.Enabled) btnStop.PerformClick();
                reader.DisConnect();

                btnConnect.Enabled = true;
                btnStart.Enabled = false;

                ConvertEnable();
            });

            if (result == -1) return -1;
            return 1;
        }

        /// <summary>
        /// 外部调用检测ActiveX是否安装成功
        /// </summary>
        /// <returns></returns>
        public string Test()
        {
            return "success";
        }

        /// <summary>
        /// 将组件安装为ActiveX
        /// </summary>
        /// <param name="isUnInstall"></param>
        public void InstallActiveX(bool isUnInstall = false)
        {
            //注册COM
            string version = typeof(System.Linq.Queryable).Assembly.ImageRuntimeVersion;
            //找32位.Net类库
            string pathDotNet32 = @"C:\windows\Microsoft.NET\Framework\" + version;
            if (Directory.Exists(pathDotNet32))
            {
                //寻找COM注册程序RegAsm
                string regAsm = Path.Combine(pathDotNet32, "RegAsm.exe");
                string comFile = Assembly.GetExecutingAssembly().Location;
                if (File.Exists(regAsm) && File.Exists(comFile))
                {
                    //注册COM
                    if (isUnInstall) comFile += " /u";
                    Process.Start(new ProcessStartInfo(regAsm, comFile) { WindowStyle = ProcessWindowStyle.Hidden });
                    MsgBox.Show("执行成功!");
                }
            }
        }

        /// <summary>
        /// 检查ActiveX是否安装成功
        /// </summary>
        public bool IsActiveXInstalled()
        {
            Type type = Type.GetTypeFromCLSID(new Guid("2079D3B4-6C55-4F47-876F-DBB874A4F68A"));
            if (type == null) return false;
            object ax = null;
            try
            {
                ax = Activator.CreateInstance(type);
            }
            catch(Exception)
            {
                return false;
            }

            MethodInfo mi = type.GetMethod("Test");
            object result = mi.Invoke(ax, null);
            if (result.ToString() == "success") return true;

            return false;
        }

        /// <summary>
        /// 补充注册项(没有此注册项的话,通过本地RegAsm注册的ActiveX无法在IE中使用)
        /// </summary>
        /// <param name="type"></param>
        [ComRegisterFunctionAttribute]
        public static void RegisterFunction(Type type)
        {
            //注册[HKEY_CLASSES_ROOT\CLSID\{6AEBC61A-EFAA-4676-8174-D431EA938DEE}\InprocServer32]下的CodeBase
            string keyPath = @"CLSID\{" + type.GUID.ToString().ToUpper() + @"}\InprocServer32";
            var keyItem = Registry.ClassesRoot.CreateSubKey(keyPath);
            keyItem.SetValue("CodeBase", Assembly.GetExecutingAssembly().Location);

            //注册不同版本的CodeBase
            string[] subKeys = keyItem.GetSubKeyNames();
            foreach (var item in subKeys)
            {
                string subKey = keyPath + @"\" + item;
                var subKeyItem = Registry.ClassesRoot.CreateSubKey(subKey);
                subKeyItem.SetValue("CodeBase", Assembly.GetExecutingAssembly().Location);
            }
        }

        /// <summary>
        /// 取消注册项
        /// </summary>
        /// <param name="type"></param>
        [ComUnregisterFunctionAttribute]
        public static void UnregisterFunction(Type type)
        {
            //删除注册[HKEY_CLASSES_ROOT\CLSID\{6AEBC61A-EFAA-4676-8174-D431EA938DEE}\InprocServer32]下的CodeBase
            string keyPath = @"CLSID\{" + type.GUID.ToString().ToUpper() + @"}\InprocServer32";
            var keyItem = Registry.ClassesRoot.CreateSubKey(keyPath);
            keyItem.DeleteValue("CodeBase");

            //删除不同注册版本的CodeBase
            string[] subKeys = keyItem.GetSubKeyNames();
            foreach (var item in subKeys)
            {
                string subKey = keyPath + @"\" + item;
                var subKeyItem = Registry.ClassesRoot.CreateSubKey(subKey);
                subKeyItem.DeleteValue("CodeBase");
            }
        }


        #region IObjectSafety 成员
        private const string _IID_IDispatch = "{00020400-0000-0000-C000-000000000046}";
        private const string _IID_IDispatchEx = "{a6ef9860-c720-11d0-9337-00a0c90dcaa9}";
        private const string _IID_IPersistStorage = "{0000010A-0000-0000-C000-000000000046}";
        private const string _IID_IPersistStream = "{00000109-0000-0000-C000-000000000046}";
        private const string _IID_IPersistPropertyBag = "{37D84F60-42CB-11CE-8135-00AA004BB851}";

        private const int INTERFACESAFE_FOR_UNTRUSTED_CALLER = 0x00000001;
        private const int INTERFACESAFE_FOR_UNTRUSTED_DATA = 0x00000002;
        private const int S_OK = 0;
        private const int E_FAIL = unchecked((int)0x80004005);
        private const int E_NOINTERFACE = unchecked((int)0x80004002);

        private bool _fSafeForScripting = true;
        private bool _fSafeForInitializing = true;

        public int GetInterfaceSafetyOptions(ref Guid riid, ref int pdwSupportedOptions, ref int pdwEnabledOptions)
        {
            //int Rslt = E_FAIL;

            //string strGUID = riid.ToString("B");
            //pdwSupportedOptions = INTERFACESAFE_FOR_UNTRUSTED_CALLER | INTERFACESAFE_FOR_UNTRUSTED_DATA;
            //switch (strGUID)
            //{
            //    case _IID_IDispatch:
            //    case _IID_IDispatchEx:
            //        Rslt = S_OK;
            //        pdwEnabledOptions = 0;
            //        if (_fSafeForScripting == true)
            //            pdwEnabledOptions = INTERFACESAFE_FOR_UNTRUSTED_CALLER;
            //        break;
            //    case _IID_IPersistStorage:
            //    case _IID_IPersistStream:
            //    case _IID_IPersistPropertyBag:
            //        Rslt = S_OK;
            //        pdwEnabledOptions = 0;
            //        if (_fSafeForInitializing == true)
            //            pdwEnabledOptions = INTERFACESAFE_FOR_UNTRUSTED_DATA;
            //        break;
            //    default:
            //        Rslt = E_NOINTERFACE;
            //        break;
            //}

            //return Rslt;
            pdwSupportedOptions = 1;

            pdwEnabledOptions = 2;

            return S_OK;
        }

        public int SetInterfaceSafetyOptions(ref Guid riid, int dwOptionSetMask, int dwEnabledOptions)
        {
            //int Rslt = E_FAIL;
            //string strGUID = riid.ToString("B");
            //switch (strGUID)
            //{
            //    case _IID_IDispatch:
            //    case _IID_IDispatchEx:
            //        if (((dwEnabledOptions & dwOptionSetMask) == INTERFACESAFE_FOR_UNTRUSTED_CALLER) && (_fSafeForScripting == true))
            //            Rslt = S_OK;
            //        break;
            //    case _IID_IPersistStorage:
            //    case _IID_IPersistStream:
            //    case _IID_IPersistPropertyBag:
            //        if (((dwEnabledOptions & dwOptionSetMask) == INTERFACESAFE_FOR_UNTRUSTED_DATA) && (_fSafeForInitializing == true))
            //            Rslt = S_OK;
            //        break;
            //    default:
            //        Rslt = E_NOINTERFACE;
            //        break;
            //}

            //return Rslt;

            return S_OK;
        }

        #endregion
    }
}
圣殿骑士18 2018-01-12
  • 打赏
  • 举报
回复
贴一下我实现过的
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;

namespace BL.Device.RfReader.ActiveX
{
    [ComImport, GuidAttribute("CB5BDC81-93C1-11CF-8F20-00805F2CD064")]
    [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
    public interface IObjectSafety
    {
        [PreserveSig]
        int GetInterfaceSafetyOptions(ref Guid riid, [MarshalAs(UnmanagedType.U4)] ref int pdwSupportedOptions, [MarshalAs(UnmanagedType.U4)] ref int pdwEnabledOptions);

        [PreserveSig()]
        int SetInterfaceSafetyOptions(ref Guid riid, [MarshalAs(UnmanagedType.U4)] int dwOptionSetMask, [MarshalAs(UnmanagedType.U4)] int dwEnabledOptions);
    }
}
圣殿骑士18 2018-01-12
  • 打赏
  • 举报
回复
是不是com对象中,少了这个定义
/// <summary>
        /// 补充注册项(没有此注册项的话,通过本地RegAsm注册的ActiveX无法在IE中使用)
        /// </summary>
        /// <param name="type"></param>
        [ComRegisterFunctionAttribute]
        public static void RegisterFunction(Type type)
        {
            //注册[HKEY_CLASSES_ROOT\CLSID\{6AEBC61A-EFAA-4676-8174-D431EA938DEE}\InprocServer32]下的CodeBase
            string keyPath = @"CLSID\{" + type.GUID.ToString().ToUpper() + @"}\InprocServer32";
            var keyItem = Registry.ClassesRoot.CreateSubKey(keyPath);
            keyItem.SetValue("CodeBase", Assembly.GetExecutingAssembly().Location);

            //注册不同版本的CodeBase
            string[] subKeys = keyItem.GetSubKeyNames();
            foreach (var item in subKeys)
            {
                string subKey = keyPath + @"\" + item;
                var subKeyItem = Registry.ClassesRoot.CreateSubKey(subKey);
                subKeyItem.SetValue("CodeBase", Assembly.GetExecutingAssembly().Location);
            }
        }

        /// <summary>
        /// 取消注册项
        /// </summary>
        /// <param name="type"></param>
        [ComUnregisterFunctionAttribute]
        public static void UnregisterFunction(Type type)
        {
            //删除注册[HKEY_CLASSES_ROOT\CLSID\{6AEBC61A-EFAA-4676-8174-D431EA938DEE}\InprocServer32]下的CodeBase
            string keyPath = @"CLSID\{" + type.GUID.ToString().ToUpper() + @"}\InprocServer32";
            var keyItem = Registry.ClassesRoot.CreateSubKey(keyPath);
            keyItem.DeleteValue("CodeBase");

            //删除不同注册版本的CodeBase
            string[] subKeys = keyItem.GetSubKeyNames();
            foreach (var item in subKeys)
            {
                string subKey = keyPath + @"\" + item;
                var subKeyItem = Registry.ClassesRoot.CreateSubKey(subKey);
                subKeyItem.DeleteValue("CodeBase");
            }
        }
assky124 2018-01-12
  • 打赏
  • 举报
回复
这个技术早就被淘汰了。 换台电脑试试
  • 打赏
  • 举报
回复
引用 10 楼 Win32FanPro 的回复:
[quote=引用 8 楼 assky124 的回复:] 有安装包,你还搞ActiveX,直接用自定义协议启动你的程序就行了
我要让控件嵌入到IE窗口中去,除了ActiveX,请问还有什么技术可以做到?[/quote] ppapi,npapi 是现在流行的。
assky124 2018-01-12
  • 打赏
  • 举报
回复
新版本的IE都开始不支持ActiveX。嵌入的话Flash可以,不过也逐渐被淘汰了。 启动一个外部程序就完了,就像迅雷下载一样。 http://blog.csdn.net/cainiaokan/article/details/44103361
圣殿骑士18 2018-01-12
  • 打赏
  • 举报
回复
也没帮上忙,红包就不用了。可以加个q,互相交流学习 363600392。 另外,我现在是已经放弃了使用activex了,解决问题很啰嗦,因为客户端的差异性,部署也不稳定。我当时调试通过,大概研究步骤有二十多个,一步步解决各种坑。 对于本地化的解决,我现在是采用本地的exe或者服务的小程序+websocket,实现由网页直接控制小程序终端来实现pc终端能力,这种方式更稳定。
xiwuyuan 2018-01-12
  • 打赏
  • 举报
回复
你可以尝试用ACTIVEMQ 这种消息机制取代ActiveX 这样的话起码是不挑浏览器了
大狗狗 2018-01-12
  • 打赏
  • 举报
回复
引用 11 楼 tangyanzhi1111 的回复:
IE 微软都不支持,同理COM也是被丢弃的技术,搞这玩意, 那是比较蛋疼的
请问什么可以替代ActiveX技术?
江湖评谈 2018-01-12
  • 打赏
  • 举报
回复
IE 微软都不支持,同理COM也是被丢弃的技术,搞这玩意, 那是比较蛋疼的
Win32FanPro 2018-01-12
  • 打赏
  • 举报
回复
引用 8 楼 assky124 的回复:
有安装包,你还搞ActiveX,直接用自定义协议启动你的程序就行了
我要让控件嵌入到IE窗口中去,除了ActiveX,请问还有什么技术可以做到?
神马都能聊 2018-01-12
  • 打赏
  • 举报
回复
AX、OCX、COM有编译兼容问题,你检查一下编译和使用是不是做到了覆盖。
assky124 2018-01-12
  • 打赏
  • 举报
回复
有安装包,你还搞ActiveX,直接用自定义协议启动你的程序就行了

110,525

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧