代码之家  ›  专栏  ›  技术社区  ›  Ron Klein Noa Kuperberg

对非托管代码的C++/CLI传递(托管)委托

  •  25
  • Ron Klein Noa Kuperberg  · 技术社区  · 15 年前

    如何将函数指针从托管C++(C++/CLI)传递到非托管方法?我读了几篇文章,比如 this one from MSDN 但它描述了两个不同的程序集,而我只需要一个。

    这是我的代码:

    1)标题(myinterop.managedapplib.h):

    #pragma once
    
    using namespace System;
    
    namespace MyInterop { namespace ManagedCppLib {
    
        public ref class MyManagedClass
        {
        public:
            void DoSomething();
        };
    }}
    

    2)CPP代码(myinterop.managedpplib.cpp)

    #include "stdafx.h"
    #include "MyInterop.ManagedCppLib.h"
    
    #pragma unmanaged
    void UnmanagedMethod(int a, int b, void (*sum)(const int))
    {
        int result = a + b;
        sum(result);
    }
    
    #pragma managed
    void MyInterop::ManagedCppLib::MyManagedClass::DoSomething()
    {
        System::Console::WriteLine("hello from managed C++");
        UnmanagedMethod(3, 7, /* ANY IDEA??? */);
    }
    

    我尝试创建托管委托,然后尝试使用 Marshal::GetFunctionPointerForDelegate 方法,但我无法编译。

    1 回复  |  直到 8 年前
        1
  •  41
  •   Hans Passant    8 年前

    是的,您需要marshal::GetFunctionPointerForDelegate()。您的代码段缺少您想要调用的托管函数,我只是编了一个。在获得函数指针之前,还必须声明托管委托类型并创建它的实例。这很有效:

    #include "stdafx.h"
    
    using namespace System;
    using namespace System::Runtime::InteropServices;
    
    #pragma managed(push, off)
    typedef void (* UnmanagedSummer)(int arg);
    
    void UnmanagedMethod(int a, int b, UnmanagedSummer sum)
    {
        int result = a + b;
        sum(result);
    }
    #pragma managed(pop)
    
    ref class Test {
        delegate void ManagedSummer(int arg);
    public:
        static void Run() {
            Test^ t = gcnew Test();
            ManagedSummer^ managed = gcnew ManagedSummer(t, &Sum);
            IntPtr stubPointer = Marshal::GetFunctionPointerForDelegate(managed);
            UnmanagedSummer functionPointer = static_cast<UnmanagedSummer>(stubPointer.ToPointer());
            UnmanagedMethod(1, 2, functionPointer);
            GC::KeepAlive(managed);    // Important: ensure stub can't be collected while native code is running
            System::Diagnostics::Debug::Assert(t->summed == 3);
        }
        void Sum(int arg) {
            summed += arg;
        }
        int summed;
    };
    
    int main(array<System::String ^> ^args)
    {
        Test::Run();
        return 0;
    }