函数委托_ZC

1、函数委托 类似于 C++中函数指针(∵我不知道这两货是否真的完全一样,∴用的是"类似于")

2、声明函数委托 方法类似于 声明函数指针

3、我的代码:

  3.1、VC的DLL代码:

// *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
// 普通导出函数

extern "C" __declspec(dllexport) int __stdcall TestZZ(int i, int j, int k, int m, int n)
{
    return (i+j+k+m+n);
}

// *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
// exe中传入回调函数指针,并且调用

typedef int (__stdcall * Callback_Test01)(int, int, int, int, int);

extern "C" __declspec(dllexport) void __stdcall TestCB(Callback_Test01 _callback)
{
    if (_callback)
    {
        int i = _callback(1,2,3,4,5);
    }
}

    3.1.1、def文件内容:

LIBRARY DLL_Z
EXPORTS
    TestZZ
    TestCB

  3.2、C#代码:

        private void button1_Click(object sender, EventArgs e)
        {
            AAA(1, 2, 3); // 用汇编查看 调用普通C#函数时的调用规则
            int kk = TestZZ(1, 2, 3, 4 ,5); // 查看调用DLL导出函数时的调用规则

            Fhh = 0;
            TestCB(callback);   // ZC: 将函数委托传递给 VC的DLL 并在DLL中调用 -- (1)
            MessageBox.Show(Fhh.ToString());

            Fhh = 0;
            callback02 = new Callback_Test01(TT01);
            TestCB(callback02); // ZC: 将函数委托传递给 VC的DLL 并在DLL中调用 -- (2)
            MessageBox.Show(Fhh.ToString());
        }

        int AAA(int i, int j, int k)
        {
            return (i + j + k);
        }

        //[DllImport("DLL_Z.dll", EntryPoint="TestZZ", CharSet=CharSet.Auto, CallingConvention=CallingConvention.StdCall)]
        [DllImport("DLL_Z.dll", EntryPoint = "TestZZ", CharSet = CharSet.Auto)]
        public static extern int TestZZ(Int32 i, Int32 j, Int32 k, Int32 m, Int32 n);

        [DllImport("DLL_Z.dll", EntryPoint = "TestCB", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
        public static extern void TestCB([MarshalAs(UnmanagedType.FunctionPtr)] Callback_Test01 _callback);

        // (委托)回调函数指针
        [UnmanagedFunctionPointer(CallingConvention.StdCall)]
        public delegate int Callback_Test01(int _i, int _j, int _k, int _m, int _n);

        public static int Fhh = 0;

        // 委托(回调函数) -- 方式(1)
        // 需要访问类成员变量的回调函数实例
        Callback_Test01 callback =
            (i, j, k, m, n) =>
            {
                Fhh = (i + j + k + m + n); // 这里可以直接访问 类成员变量
                //return (i + j + k + m + n);
                return Fhh;
            };


        Callback_Test01 callback02 = null;//new Callback_Test01(TT01);

        // 委托(回调函数) -- 方式(2)
        int TT01(int i, int j, int k, int m, int n)
        {
            Fhh = (i + j + k + m + n); // 这里可以直接访问 类成员变量
            //return (i + j + k + m + n);
            return Fhh;
        }

  ZC: 测试感受:

  ZC: (1)、C#调用DLL中的函数,貌似默认的调用约定是 stdcall

  ZC: (2)、delegate 貌似它的默认调用约定也是stdcall

 

 

 

 

 

 

 

4、这里 测试的是 VC的DLL返回接口 让C#使用

  4.1、C#代码:

    4.1.1、接口声明

namespace WindowsFormsApplication_AAA
{
    [Guid("FCE9DCF3-9E38-441C-B10F-2BA31B57DCDC")]
    [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    public interface IntfTest
    {
        unsafe Int32 TestZ01(int _i, int _j, int _k, int* _piOut);
        unsafe Int32 TestZ02(int _i, int _j, int _k, int _m, int* _piOut);
        unsafe Int32 TestZ03(int _i, int _j, int _k, int _m, int _n, int* _piOut);
    }
}

    4.1.2、

        [DllImport("DLL_Z.dll", EntryPoint = "IntfTest_Get", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl)]
        public static extern int IntfTest_Get(ref IntfTest _intfTest);

        private void button2_Click(object sender, EventArgs e)
        {
            callback02 = new Callback_Test01(TT01);

            // 操作/使用 DLL返回的接口
            IntfTest intfTest = null;
            int iRtn = IntfTest_Get(ref intfTest);

            unsafe
            {
                int iOut = 0;
                intfTest.TestZ01(1, 2, 3, &iOut);
            }
        }

  4.2、VC的DLL中的代码:

    4.2.1、

// *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
// 导出 interface,供 exe使用

IntfTest *g_pIntfTest;

extern "C" __declspec(dllexport) int IntfTest_Get(IntfTest **_ppIntfTest)
{
    (*_ppIntfTest) = NULL;

    if ( NULL != g_pIntfTest )
    {
        // 当"IntfTest*"为局部变量时,C#会自动销毁接口,使得引用计数-1,∴这里需要+1
        // 而 首次获取"IntfTest*"时,由于类构造函数中有增加引用计数的操作,∴不需要+1
        g_pIntfTest->AddRef();
        (*_ppIntfTest) = g_pIntfTest;
        return 0;
    }

// ***
    IntfTest *pObj = new TintfTest();

    IUnknown *pIUnknown = NULL;
    HRESULT hr = pObj->QueryInterface(IID_IUnknown, (void**)&pIUnknown);
    pObj->Release();
    pObj = NULL;

    if (FAILED(hr))
    {
        return -1;
    }
    else
    {
        hr = pIUnknown->QueryInterface(IID_IntfTest, (void**)&g_pIntfTest);
        pIUnknown->Release();
        pIUnknown = NULL;

        if (SUCCEEDED(hr))
        {
            (*_ppIntfTest) = g_pIntfTest;
        }
        else
        {
            return -2;
        }
    }
    return 0;
}

    4.2.2、接口信息:

#ifndef __zzz_20160414__
#define __zzz_20160414__

#include <Unknwn.h>

// // {FCE9DCF3-9E38-441C-B10F-2BA31B57DCDC}
static const IID IID_IntfTest =
{ 0xfce9dcf3, 0x9e38, 0x441c, { 0xb1, 0xf, 0x2b, 0xa3, 0x1b, 0x57, 0xdc, 0xdc } };


interface IntfTest : public IUnknown
{
    virtual HRESULT __stdcall TestZ01(int _i, int _j, int _k, int* _piOut) = 0;
    virtual HRESULT __stdcall TestZ02(int _i, int _j, int _k, int _m, int* _piOut) = 0;
    virtual HRESULT __stdcall TestZ03(int _i, int _j, int _k, int _m, int _n, int* _piOut) = 0;
};

class TintfTest :public IntfTest
{
public:
    TintfTest();

public:
    virtual HRESULT __stdcall TestZ01(int _i, int _j, int _k, int* _piOut);
    virtual HRESULT __stdcall TestZ02(int _i, int _j, int _k, int _m, int* _piOut);
    virtual HRESULT __stdcall TestZ03(int _i, int _j, int _k, int _m, int _n, int* _piOut);

private:
    long FlCount;
public:
    virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void **ppv)
    {
        if (iid == IID_IUnknown)
        {
            *ppv = static_cast<IntfTest*>(this);
        }
        else if (iid == IID_IntfTest)
        {
            *ppv = static_cast<IntfTest*>(this);
        }
        else
        {
            *ppv = NULL;
            return E_NOINTERFACE;
        }

        AddRef();

        return S_OK;
    }

    virtual ULONG STDMETHODCALLTYPE AddRef()
    {
        return ++FlCount;

        //return InterlockedIncrement(&FlCount);
    }

    virtual ULONG STDMETHODCALLTYPE Release()
    {
        if (--FlCount == 0)
        {
            delete this;
            return 0;
        }
        return FlCount;

        //if (InterlockedDecrement(&FlCount) == 0)
        //{
        //    delete this;
        //    return 0;
        //}
        //return FlCount;
    }
};

TintfTest::TintfTest():
    FlCount(0)
{
    this->AddRef();
}

HRESULT __stdcall TintfTest::TestZ01(int _i, int _j, int _k, int* _piOut)
{
    *_piOut = (_i + _j + _k);
    return S_OK;
}

HRESULT __stdcall TintfTest::TestZ02(int _i, int _j, int _k, int _m, int* _piOut)
{
    return S_OK;
}

HRESULT __stdcall TintfTest::TestZ03(int _i, int _j, int _k, int _m, int _n, int* _piOut)
{
    return S_OK;
}


#endif // __zzz_20160414__

 

5、

 

posted @ 2016-06-02 13:56  csskill  阅读(269)  评论(0编辑  收藏  举报