c#开发的客户端,如何调用c++开发的sdk dll库

2021-05-18 10:36:04 浏览数 (1)

一、整体思路

c#客户端不能直接调用c dll,需要做2个黏合层把它们连接起来,这里以trtc sdk的dll为例

二、实现步骤

1.  先写个从c#客户端调用c dll完成trtc初始化的功能

(1) 创建一个c#客户端(选择windowsform)项目
(2) 在程序入口main()函数中,加入InitWrapper()准备用来初始化trtc sdk

Program.cs

代码语言:txt复制
//初始化TRTC SDK 
//调用链路:WindowsFormsApp1.exe(c#) -> RTCManager.dll(c#) -> TRTCWrapper.dll(c  ) -> liteav.dll(c  ,要调用的目标dll)
int nRet = RTCWrapper.InitWrapper();

(3) 创建RTCManager.dll(选择.netframework库)c# 项目
(4) 创建RTCWrapper c#类,并用DllImport映射c dll中的接口InitWrapper()

TRTCWrapper.cs

代码语言:txt复制
public static class RTCWrapper
{
        /// <summary>
        /// 初始化TRTC
        /// </summary>
        /// <returns>1成功,0失败</returns>
        [DllImport("TRTCWrapper.dll", EntryPoint = "InitWrapper")]
        public static extern int InitWrapper();
}

(5) 创建TRTCWrapper.dll(选择动态链接库) c 项目
(6) 实现InitWrapper接口

TRTCWrapper.h

代码语言:txt复制
//初始化TRTC
extern "C" __declspec(dllexport) int _stdcall InitWrapper();

TRTCWrapper.cpp

代码语言:txt复制
_declspec(dllexport) int _stdcall InitWrapper()
{
    trtcInstance = TRTCCloudCore::GetInstance();
 
    if (trtcInstance)
    {
        trtcInstance->Init();
        return 1;
    }
    else
        return 0;
}

(7) 在GetInstance()中加载trtc sdk的dll库,注意这里要用动态加载dll的方式,不然编译不过。Init()有其他作用,可以用来设置回调

TRTCCloudCore.cpp

代码语言:txt复制
TRTCCloudCore* TRTCCloudCore::GetInstance()
{
    if (m_instance == NULL) {
        engine_mex.lock();
        if (m_instance == NULL)
        {
            m_instance = new TRTCCloudCore();
        }
        engine_mex.unlock();
    }
    return m_instance;
}
 
TRTCCloudCore::TRTCCloudCore()
{
    trtc_module_ = nullptr;
    if (trtc_module_ != nullptr) return;
 
    HMODULE hmodule = NULL;
    GetModuleHandleEx(
        GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
        L"TRTCModule", &hmodule);
 
    char module_path[MAX_PATH] = { 0 };
    ::GetModuleFileNameA(hmodule, module_path, _countof(module_path));
 
    std::string module_dir = GetPathNoExt(module_path);
    if (module_dir.length() == 0) {
        LINFO(L"TRTC GetModule Path Error");
        return;
    }
 
    std::string module_full_path = module_dir   "liteav.dll";
 
    trtc_module_ =
        ::LoadLibraryExA(module_full_path.c_str(), NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
}

注意:

1.设置项目之间的依赖关系

2.添加trtc对应的include,lib目录

3.设置dll的生成目录,跟c# exe在一起,这样方便调试,不用写脚本copy

2. 接着实现sdk的回调通知给主程序

(1) 在程序入口main()函数中,加入AddTRTCMsgCallBack()准备用来注册trtc的回调

Program.cs

代码语言:txt复制
//注册SDK的callback
RTCDelegate rtcDelegate = new RTCDelegate();
RTCWrapper.AddTRTCMsgCallBack(rtcDelegate.rtcCallBack);

(2) 在RTCManager.dll中实现RTCDelegate c#类,用来接收trtc sdk的回调

RTCDelegate.cs

代码语言:txt复制
enum TRTC_MSG
{
    TRTC_MSG_onEnterRoom = 1,
    TRTC_MSG_onExitRoom,
    TRTC_MSG_onRemoteUserEnterRoom,
    TRTC_MSG_onRemoteUserLeaveRoom,
    TRTC_MSG_onError,
    TRTC_MSG_onWarning
    //TODO 补齐TRTC的回调
};
 
namespace RTCManager
{
    [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
    public delegate void RTCWrapperCallback(int trtcModule, int errCode, [In, MarshalAs(UnmanagedType.LPStr)] string errMsg);
 
 
    public class RTCDelegate
    {
        public RTCWrapperCallback rtcCallBack = null;
 
        public RTCDelegate()
        {
            Setcallback();
        }
 
        private void RTCWrapperCallbackFun(int trtcModule, int errCode, [In, MarshalAs(UnmanagedType.LPStr)] string errMsg)
        {
            TRTC_MSG trtcMsg = (TRTC_MSG)trtcModule;
            switch (trtcMsg)
            {
                case TRTC_MSG.TRTC_MSG_onEnterRoom:
                    break;
                default:
                    break;
 
            }
        }
 
        public void Setcallback()
        {
            rtcCallBack = RTCWrapperCallbackFun;
        }
         
    }
}

(3) 用DllImport映射c dll中的接口AddTRTCMsgCallBack()

TRTCWrapper.cs

代码语言:txt复制
/// <summary>
/// 注册TRTC通用回调
/// </summary>
/// <param name="callback">通用回调</param>
/// <returns></returns>
[DllImport("TRTCWrapper.dll", EntryPoint = "AddTRTCMsgCallBack")]
public static extern void AddTRTCMsgCallBack(RTCWrapperCallback callback);

(4) 在TRTCWrapper.dll中实现AddTRTCMsgCallBack()接口

TRTCWrapper.h

代码语言:txt复制
//注册TRTC通用回调
extern "C" __declspec(dllexport) void _stdcall AddTRTCMsgCallBack(TRTCMsgCallback messageCallback);

TRTCWrapper.cpp

代码语言:txt复制
_declspec(dllexport) void _stdcall AddTRTCMsgCallBack(TRTCMsgCallback messageCallback)
{
    if(trtcInstance)
        trtcInstance->MessageCallBack = messageCallback;
    //else 输出错误日志
}

(5) 把messageCallback设置到trtc sdk中

TRTCCloudCore.h

代码语言:txt复制
typedef void(*TRTCMsgCallback)(int trtcModule, int errCode, const wchar_t* errMsg);
 
TRTCMsgCallback MessageCallBack = nullptr;

(6) 在trtc sdk的回调接口onEnterRoom中调用messageCallback

TRTCCloudCore.cpp

代码语言:txt复制
void TRTCCloudCore::onEnterRoom(int result)
{
    if (MessageCallBack)
        MessageCallBack(TRTC_MSG_onEnterRoom, result, L"");
}

(7) Debug一下看看能不能回调到c#中

3. 让trtc sdk的视频在c#程序中显示

(1) 在c#程序窗口中,添加个button用来测试

Form1.cs

代码语言:txt复制
private void button1_Click(object sender, EventArgs e)
{
            IntPtr hwnd = this.Handle;
            RTCWrapper.EnterRoom(0,
                "",
                "",
                0);
            RTCWrapper.StartLocalPreview(hwnd);
            RTCWrapper.StartLocalAudio();
}

(2) 用DllImport映射c dll中的接口StartLocalPreview()

TRTCWrapper.cs

代码语言:txt复制
[DllImport("TRTCWrapper.dll", EntryPoint = "StartLocalPreview")]
public static extern void StartLocalPreview(IntPtr hwnd);

(3) 在TRTCWrapper.dll中实现StartLocalPreview()接口

TRTCWrapper.h

代码语言:txt复制
//开启本地预览
extern "C" __declspec(dllexport) void _stdcall StartLocalPreview(HWND hwnd);

TRTCWrapper.cpp

代码语言:txt复制
_declspec(dllexport) void _stdcall StartLocalPreview(HWND hwnd)
{
    if (trtcInstance)
        trtcInstance->startPreview(hwnd);
    //else 输出错误日志
}

(4) 调用trtc sdk本地视频预览接口

TRTCCloudCore.cpp

代码语言:txt复制
void TRTCCloudCore::startPreview(HWND hwnd)
{
    if (m_pCloud == nullptr)
        return;
 
    if (m_bStartLocalPreview)
        return;
 
    if (!hwnd)
        return;
 
    m_pCloud->startLocalPreview(hwnd);
    m_bStartLocalPreview = true;
}

(5) 用相同的方法实现enterRoom、startLocalAudio

注意:

c#调用c dll,因为是DllImport动态引用,所以debug时进不了c 代码;

可以写个简单的mfc exe,用静态引用的方式引用TRTCWrapper.lib和liteav.lib,就可以debug c 的代码了。

需要源码可以发邮件到tomas7571@qq.com

0 人点赞