• 在VB6中使用。net DLL


    介绍 本文的目的是帮助有兴趣将VB6应用程序迁移到。net (c#或VB.NET)或使用。net现代资源改进VB6应用程序的团队。将VB6项目完全迁移到。net可能代价高昂且复杂。这里描述的方法允许您每次转换一小段代码。另一种可能是不转换任何代码,而是直接在. net中添加新的需求,避免增加遗留应用程序。 背景 有几篇文章帮助创建。net用户控件,以便在VB6应用程序中使用。这种方法简化了这个过程,使用c#开发的通用COM程序集,它使用反射来调用我们想要的任何另一个DLL。有了这个通用DLL,我们只需要在操作系统中注册一个,并封装了许多复杂的代码。当您的环境中有多台机器时,不需要在OS中注册多个DLL是很有用的。 使用的代码 创建COM程序集 在Visual Studio中,创建一个新的类库项目。在“项目属性”中,单击“应用程序”选项卡,单击“程序集信息”按钮,选中“使程序集COM-Visible”选项。在Build选项卡中,检查COM互操作的选项寄存器。 在项目中添加一个新类CSharpInteropService.cs。 下面的接口公开了用于调用VB6应用程序中的操作的事件。它允许打开一个尚未转换的VB6表单。 隐藏,复制Code

    [ComVisible(true), Guid(LibraryInvoke.EventsId), InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
    public interface ILibraryInvokeEvent
    {
        [DispId(1)]
        void MessageEvent(string message);
    }

    下面的接口公开了用于调用DLL的方法。 隐藏,复制Code

    [ComVisible(true), Guid(LibraryInvoke.InterfaceId)]
    public interface ILibraryInvoke
    {
        [DispId(1)]
        object[] GenericInvoke(string dllFile, string className, string methodName, object[] parameters);
    }

    下面的类是接口的实现。GenericInvoke接收将使用反射调用的DLL完整补丁、类名和方法名。您可以发送一个参数数组。最后,它会返回一个数组。GenericInvoke期望DLL目标中的MessageEvent方法创建带有OnMessageEvent的委托。只有当您希望与VB6通信时,才需要在目标中声明MessageEvent。 隐藏,收缩,复制Code

    [ComVisible(true), Guid(LibraryInvoke.ClassId)]
    [ComSourceInterfaces("CSharpInteropService.ILibraryInvokeEvent")]
    [ComClass(LibraryInvoke.ClassId, LibraryInvoke.InterfaceId, LibraryInvoke.EventsId)]
    public class LibraryInvoke : ILibraryInvoke
    {
        public const string ClassId = "3D853E7B-01DA-4944-8E65-5E36B501E889";
        public const string InterfaceId = "CB344AD3-88B2-47D8-86F1-20EEFAF6BAE8";
        public const string EventsId = "5E16F11C-2E1D-4B35-B190-E752B283260A";
    
        public delegate void MessageHandler(string message);
        public event MessageHandler MessageEvent;
    
        public object[] GenericInvoke(string dllFile, string className, 
                                      string methodName, object[] parameters)
        {
            Assembly dll = Assembly.LoadFrom(dllFile);
    
            Type classType = dll.GetType(className);
            object classInstance = Activator.CreateInstance(classType);
            MethodInfo classMethod = classType.GetMethod(methodName);
    
            EventInfo eventMessageEvent = classType.GetEvent
                     ("MessageEvent", BindingFlags.NonPublic | BindingFlags.Static);
    
            if (eventMessageEvent != null)
            {
                Type typeMessageEvent = eventMessageEvent.EventHandlerType;
    
                MethodInfo handler = typeof(LibraryInvoke).GetMethod
                        ("OnMessageEvent", BindingFlags.NonPublic | BindingFlags.Instance);
                Delegate del = Delegate.CreateDelegate(typeMessageEvent, this, handler);
    
                MethodInfo addHandler = eventMessageEvent.GetAddMethod(true);
                Object[] addHandlerArgs = { del };
                addHandler.Invoke(classInstance, addHandlerArgs);
            }
    
            return (object[])classMethod.Invoke(classInstance, parameters);
        }
    
        private void OnMessageEvent(string message)
        {
            MessageEvent?.Invoke(message);
        }
     }

    注册COM组件 在构建项目之后,您将获得一个DLL和TLB文件。您需要使用regas .exe工具(32位)注册这个程序集。这个工具位于你的。net框架版本的c:c模块。 隐藏,复制Code

    C:WindowsMicrosoft.NETFrameworkv4.0.30319RegAsm.exe /codebase 
    "C:TempCSharpInteropCSharpInteropServiceCSharpInteropServiceinDebugCSharpInteropService.dll" 
    /tlb:"C:TempCSharpInteropCSharpInteropServiceCSharpInteropServiceinDebugCSharpInteropService.tlb"

    要取消注册,请使用/u而不是/codebase。 如果您尝试从一个网络位置注册CSharpInteropService.dll并收到一个错误,可能有必要在regams .exe中包括以下几行。配置键内的配置: 隐藏,复制Code

    <runtime>
        <loadFromRemoteSourcesenabled="true"/>
    </runtime>
    

    调用DLL 注册了程序集后,只需在VB6项目引用处选择它。下面的代码显示了如何进行基本调用。 隐藏,复制Code

    Dim param(0) As Variant
    param(0) = Me.hWnd 'To made the c# form a child of vb6 mdi
       
    Dim load As New LibraryInvoke
    Set CSharpInteropServiceEvents = load
      
    load.GenericInvoke "C:TempCSharpInteropClassLibrary1ClassLibrary1inDebugClassLibrary1.dll", 
    "ClassLibrary1.Class1", "ShowFormParent", param

    c# DLL 隐藏,复制Code

    [DllImport("user32.dll")]
    public static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);
    
    public void ShowFormParent(long parent)
    {
        Form1 form = new Form1();
        form.Show();
    
        IntPtr p = new IntPtr(parent);
        SetParent(form.Handle, p);
    }
    
    private delegate void MessageHandler(string message);
    private static event MessageHandler MessageEvent = delegate { };
    
    public static void OnMessageEvent(string message)
    {
        MessageEvent(message);
    }

    网络环境 如果您尝试从网络位置加载程序集并接收到异常(System.IO.FileLoadException),请尝试为VB6可执行文件创建配置文件。在我的示例项目中,我创建了一个Project1.exe。为Project1.exe配置如下内容: 隐藏,复制Code

    <?xmlversion="1.0"encoding="utf-8"?>
    <configuration>
       <runtime>
          <loadFromRemoteSourcesenabled="true"/>
       </runtime>
    </configuration>

    限制 在当前阶段,当使用ShowDialog()打开c#表单时,会有一个限制。在这种情况下,VB6中的事件不会在打开表单时调用,而是在打开表单之前和关闭表单之后,通信会正常工作。 本文转载于:http://www.diyabc.com/frontweb/news2206.html

  • 相关阅读:
    c#使用selenium过滑动验证码
    C#构建数据类型不同的链表
    【疑难杂症】c#控制台应用程序卡输出
    只需三步,轻松体验office2019
    一文搞定C#.Net如何调用/交互Javascript
    逆向某微信小程序参数签名算法
    win10 IIS疑难杂症--处理程序“ExtensionlessUrlHandler-Integrated-4.0”在其模块列表中有一个错误模块“ManagedPipelineHandler”
    一台手机如何在微信语音/视频通话时把声音录下来
    android端日志查看调试利器Logcat Reader
    [开源]安卓调试神器-获取最上层Activity:TopActivity
  • 原文地址:https://www.cnblogs.com/Dincat/p/13457308.html
Copyright © 2020-2023  润新知