RError.com

RError.com Logo RError.com Logo

RError.com Navigation

  • 主页

Mobile menu

Close
  • 主页
  • 系统&网络
    • 热门问题
    • 最新问题
    • 标签
  • Ubuntu
    • 热门问题
    • 最新问题
    • 标签
  • 帮助
主页 / 问题 / 589886
Accepted
Pavel Mayorov
Pavel Mayorov
Asked:2020-11-11 21:08:59 +0000 UTC2020-11-11 21:08:59 +0000 UTC 2020-11-11 21:08:59 +0000 UTC

如何以最简单的方式通过COM结交C++和C#朋友?

  • 772

使用 COM 的所有秘诀包括创建类型库、将其注册到注册表中、将其注册到服务器的注册表中……

在 DLL 中,您需要创建一个对象工厂。

如果在 C# 中有一个可执行文件而在 C++ 中有一个 DLL - 是否可以不执行所有这些步骤而只加载 dll?

c#
  • 3 3 个回答
  • 10 Views

3 个回答

  • Voted
  1. Best Answer
    Pavel Mayorov
    2020-11-11T21:08:59Z2020-11-11T21:08:59Z

    是的你可以。COM 技术不需要在注册表中进行任何注册即可使用!

    问题中列出的所有步骤都需要减少模块的连接性。如果这些步骤不适合你,不需要,或者你懒得做,你可以跳过它们。

    这是一个最小的工作示例。

    C#

    using System;
    using System.Runtime.InteropServices;
    
    [ComVisible(true), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    interface ICallback
    {
        void execute();
    }
    
    class Program : ICallback
    {
        static void Main(string[] args)
        {
            SetCallbacks(new Program());
        }
    
        [DllImport("mylib", CallingConvention=CallingConvention.StdCall)]
        static extern void SetCallbacks(ICallback callback);
    
        void ICallback.execute()
        {
            Console.WriteLine("Hello, world!");
        }
    }
    

    C++

    #include "windows.h"
    
    interface ICallback : IUnknown
    {
        virtual HRESULT __stdcall execute() = 0;
    };
    
    
    extern "C" __declspec(dllexport) void __stdcall SetCallbacks(ICallback *cb) {
        cb->execute();
    }
    

    在上面的示例中,双语界面是独立编写的。原则上,这是双重工作——因此只编写一次界面,然后导入它是有意义的。

    如果接口是在 IDL 语言的 C++ 项目中编译的,那么将类型库作为依赖项包含到 C# 项目中就足够了。无需注册!

    如果接口是在C#项目中编译的,那么除了上面列出的属性之外,还需要为它设置一个属性Guid并公开。之后就可以通过tlbexp把类型库拉出来,连接到C++工程中了。同样,不需要在注册表中注册类型库。

    • 7
  2. Serginio
    2020-11-16T19:18:18Z2020-11-16T19:18:18Z

    我将添加 C++ 代码与 .Net Core 交互的可能性。在 .Net Core 中,可以通过使用本机的 coreclr.dll 来调用静态 .Net 方法。请参阅此处的示例和链接从非托管代码跨平台使用 .Net 类。或 Linux 上 IDispatch 的类似物

    因此,您可以将本机方法传入和传出托管代码。但我对对象和虚拟方法的使用很感兴趣。因此,我问了一个问题并得到了答案.Net Core Calling virtual methods of native objects 同时,for 1 method call 有一堆QueryInterface, AddRef and Release, 这个必须要考虑

    我会举我的例子。

    让我们用 C++ 描述这个类

    struct ICallback : IUnknown
    {
    public:
    
    
    
    
        // Унаследовано через IUnknown
        virtual HRESULT __stdcall QueryInterface(REFIID riid, void ** ppvObject) override;
    
        virtual ULONG __stdcall AddRef(void) override;
    
        virtual ULONG __stdcall Release(void) override;
    
        virtual HRESULT __stdcall execute(int value);
    
    };
    
    typedef void(STDMETHODCALLTYPE *ManagedRunCallback)(ICallback*);
    

    执行

     // {FFB46654-083E-486A-94B8-E28B5C01561D}
            static const GUID IID_ICallback =
            { 0xffb46654, 0x83e, 0x486a,{ 0x94, 0xb8, 0xe2, 0x8b, 0x5c, 0x1, 0x56, 0x1d } };
    
    
    
    
            HRESULT __stdcall ICallback::execute(int value)
            {
    
                wprintf_s(L"ICallback from.Net %d\n", value);
                return NOERROR;
            }
    
            HRESULT __stdcall ICallback::QueryInterface(REFIID riid, void ** ppvObject)
            {
    
    
                if (!ppvObject)
                    return E_INVALIDARG;
    
              if (riid == IID_IUnknown)
                {
                    *ppvObject = static_cast<IUnknown*>(this);
                    return S_OK;
                }
                else if (riid == IID_ICallback)
                {
                    *ppvObject = static_cast<ICallback*>(this);
    
                    return S_OK;
                }
    
                *ppvObject = nullptr;
    
                return E_NOINTERFACE;
    
            }
    
        // Меня интересует только вызов виртуальных методов
      // без отслеживания подсчета ссылок
            ULONG __stdcall ICallback::AddRef(void)
            {
                return 1;
            }
    
            ULONG __stdcall ICallback::Release(void)
            {
                return 0;
            }
    

    现在用 C# 描述

     [ComVisible(true), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
        [Guid("FFB46654-083E-486A-94B8-E28B5C01561D")]
        public interface ICallback
        {
            void execute(int value);
        }
    

    和静态方法

     public static void CallInterface(IntPtr cb)
            {
    
                var cb2 = Marshal.GetObjectForIUnknown(cb)  as ICallback;
    
                cb2?.execute(555);
    
            }
    

    现在我可以从 C++ 调用 .Net 方法

    ManagedRunCallback  pRunCallback;
    if (!CreateDelegate(domainId, L"CallInterface", (INT_PTR*)&pRunCallback)) return false;
    
            ICallback* cb = new ICallback();
            pRunCallback(cb);
    
    • 0
  3. Serginio
    2020-11-18T19:46:57Z2020-11-18T19:46:57Z

    我将在 .Net Core 中添加一个使用 VMT 的选项。调用接口非常昂贵。C 用于转换为所需的接口并计算引用,有一堆调用 QueryInterface Addref,Release从 C# 调用接口方法

    让我们定义一个 C++ 类

    struct TestThisCall {
        public:
            virtual int  execute(int value1, int value2);
    
        };
    
        typedef void(STDMETHODCALLTYPE *ManagedRunCallback2)(TestThisCall*);
    

    让我们创建一个方法来接收VMT中的方法

    public static IntPtr ПолучитьАдресВиртуальногоМетода(IntPtr Объект, int ИндексВТаблицеВиртуальныхМетодов )
            {
                int размерIntPtr = Marshal.SizeOf<IntPtr>();
    
                // Первым полем объекта идет ссылка на VMT
                // Прочитаем её
                var АдресVMT = Marshal.ReadIntPtr(Объект);
                //  получим адрес ссылки на  метод по смещению в VMT
                var АдресМетодаVMT = АдресVMT + ИндексВТаблицеВиртуальныхМетодов * размерIntPtr;
                var АдресМетода = Marshal.ReadIntPtr(АдресМетодаVMT);
    
                return АдресМетода;
            }
    

    现在让我们定义委托描述

     [UnmanagedFunctionPointer(CallingConvention.ThisCall)]
                internal delegate int ВиртуальныйМетодОбъекта2Delegate(IntPtr self, int Число1, int Число2);
    

    以及我们将从本机调用的静态方法

    public static void CallTestThisCall(IntPtr ttc)
            {
    
                // Метод execute идет первым в VMT
                // Передаем индекс 0
                var АдресМетода = ПолучитьАдресВиртуальногоМетода(ttc, 0);
                // Получим делегат по дресу
                var execute = Marshal.GetDelegateForFunctionPointer<ВиртуальныйМетодОбъекта2Delegate>(АдресМетода);
    
                // И вызовем метод
              var res=  execute(ttc, ttc.ToInt32(), 777);
              execute(ttc, ttc.ToInt32(), res);
            }
    

    现在让我们从 C++ 中调用这个方法

    ManagedRunCallback2 pRunCallback2;
        if (!CreateDelegate(domainId, L"CallTestThisCall", (INT_PTR*)&pRunCallback2)) return false;
    
        TestThisCall* ttc = new TestThisCall();
        pRunCallback2(ttc);
    

    好吧,一个关于 RSDN .Net Core Calling virtual methods of native objects 的精彩示例

    • 0

相关问题

Sidebar

Stats

  • 问题 10021
  • Answers 30001
  • 最佳答案 8000
  • 用户 6900
  • 常问
  • 回答
  • Marko Smith

    如何停止编写糟糕的代码?

    • 3 个回答
  • Marko Smith

    onCreateView 方法重构

    • 1 个回答
  • Marko Smith

    通用还是非通用

    • 2 个回答
  • Marko Smith

    如何访问 jQuery 中的列

    • 1 个回答
  • Marko Smith

    *.tga 文件的组重命名(3620 个)

    • 1 个回答
  • Marko Smith

    内存分配列表C#

    • 1 个回答
  • Marko Smith

    常规赛适度贪婪

    • 1 个回答
  • Marko Smith

    如何制作自己的自动完成/自动更正?

    • 1 个回答
  • Marko Smith

    选择斐波那契数列

    • 2 个回答
  • Marko Smith

    所有 API 版本中的通用权限代码

    • 2 个回答
  • Martin Hope
    jfs *(星号)和 ** 双星号在 Python 中是什么意思? 2020-11-23 05:07:40 +0000 UTC
  • Martin Hope
    hwak 哪个孩子调用了父母的静态方法?还是不可能完成的任务? 2020-11-18 16:30:55 +0000 UTC
  • Martin Hope
    Qwertiy 并变成3个无穷大 2020-11-06 07:15:57 +0000 UTC
  • Martin Hope
    koks_rs 什么是样板代码? 2020-10-27 15:43:19 +0000 UTC
  • Martin Hope
    user207618 Codegolf——组合选择算法的实现 2020-10-23 18:46:29 +0000 UTC
  • Martin Hope
    Sirop4ik 向 git 提交发布的正确方法是什么? 2020-10-05 00:02:00 +0000 UTC
  • Martin Hope
    Arch ArrayList 与 LinkedList 的区别? 2020-09-20 02:42:49 +0000 UTC
  • Martin Hope
    iluxa1810 哪个更正确使用:if () 或 try-catch? 2020-08-23 18:56:13 +0000 UTC
  • Martin Hope
    faoxis 为什么在这么多示例中函数都称为 foo? 2020-08-15 04:42:49 +0000 UTC
  • Martin Hope
    Pavel Mayorov 如何从事件或回调函数中返回值?或者至少等他们完成。 2020-08-11 16:49:28 +0000 UTC

热门标签

javascript python java php c# c++ html android jquery mysql

Explore

  • 主页
  • 问题
    • 热门问题
    • 最新问题
  • 标签
  • 帮助

Footer

RError.com

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

帮助

© 2023 RError.com All Rights Reserve   沪ICP备12040472号-5