首页 > 其他分享 >P /Invoke(四)

P /Invoke(四)

时间:2022-10-09 12:34:45浏览次数:22  
标签:Invoke c# void TRTC TRTCWrapper dll trtc

一、整体思路

 

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

 

 

二、实现步骤

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

(1) 创建一个c#客户端(选择windowsform)项目

(2) 在程序入口main()函数中,加入InitWrapper()准备用来初始化trtc sdk

Program.cs

//初始化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

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

//初始化TRTC
extern "C" __declspec(dllexport) int _stdcall InitWrapper();

TRTCWrapper.cpp

_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

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

//注册SDK的callback
RTCDelegate rtcDelegate = new RTCDelegate();
RTCWrapper.AddTRTCMsgCallBack(rtcDelegate.rtcCallBack);

 

 

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

RTCDelegate.cs

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

/// <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

//注册TRTC通用回调
extern "C" __declspec(dllexport) void _stdcall AddTRTCMsgCallBack(TRTCMsgCallback messageCallback);

TRTCWrapper.cpp

_declspec(dllexport) void _stdcall AddTRTCMsgCallBack(TRTCMsgCallback messageCallback)
{
    if(trtcInstance)
        trtcInstance->MessageCallBack = messageCallback;
    //else 输出错误日志
}

 

 

(5) 把messageCallback设置到trtc sdk中

TRTCCloudCore.h

typedef void(*TRTCMsgCallback)(int trtcModule, int errCode, const wchar_t* errMsg);
 
TRTCMsgCallback MessageCallBack = nullptr;

 

 

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

TRTCCloudCore.cpp

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

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

[DllImport("TRTCWrapper.dll", EntryPoint = "StartLocalPreview")]
public static extern void StartLocalPreview(IntPtr hwnd);

 

 

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

TRTCWrapper.h

//开启本地预览
extern "C" __declspec(dllexport) void _stdcall StartLocalPreview(HWND hwnd);

TRTCWrapper.cpp

_declspec(dllexport) void _stdcall StartLocalPreview(HWND hwnd)
{
    if (trtcInstance)
        trtcInstance->startPreview(hwnd);
    //else 输出错误日志
}

 

 

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

TRTCCloudCore.cpp

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++的代码了。

标签:Invoke,c#,void,TRTC,TRTCWrapper,dll,trtc
From: https://www.cnblogs.com/xietianjiao/p/16771721.html

相关文章

  • P/Invoke(五)
    简述:在C/S架构设计下,客户端与服务端进行通信有多种方式可选,常用的就是SDK,最大的有点便是便于厂家间平台对接。本篇将从多个方面详尽描述如何使用C#调用C++SDK。目录:调用......
  • P/Invoke(二)
    最恶心的是**int[]指针的指针..后来发现其实操作最麻烦的也就是类型的对应,这个**int[] 最后竟然使用IntPtr[]接收成功了。有意思。单个IntPtr接收不了。。(主要是......
  • P/invoke(三)
    前言让拖管代码对象和非托管对象协同工作的过程称为互用性(Interoperability),通常简称为Interop。P/Invoke在托管代码与非托管代码交互式时产生一个事务(Tran......
  • P/Invoke(一)
    编写目的           我们曾经熟悉的WindowsAPI, 我们曾经花费了大量精力写的代码,难道我们就要轻易放弃吗 不过当下微软已经把向下兼容性放在很重要的位置.  ......
  • 004 反射机制——反射机制概念——Java的反射API——反射的步骤——创建对象的2种方式
    2.3.2反射机制的概念(什么是反射)反射机制指在程序运行过程中,对任意一个类都能获取其所有属性和方法,并且任意一个对象都能调用其任意一个方法。这种动态获取类和对象的信......
  • php 魔术方法 __tostring() __invoke()
    //__tostring()用于屏蔽错误信息,当需要输出错误信息时,用本函数内返回的字符串代替//__invoke()用于屏蔽错误信息,当把对象当作函数调用时,会执行本函数<?phpheader("Co......
  • 【mybatis框架学习】三、invoke方法逻辑编排
    上一篇一直有提高一个词,编排。都说编程,编程,编排也就容易理解了。 像我们常用的框架,spring、mybatis,都是将一些固有的流程,简化,抽象,编排起来,在留有可拓展的接口之后,全部......
  • android程序报错Attempt to invoke virtual method 'boolean java.lang.String.equals
    android程序报错运行报以下错误:Attempttoinvokevirtualmethod'booleanjava.lang.String.equals(java.lang.Object)'onanullobjectreference可能原因:1、可能布......
  • Invoke-PSImage 使用简介
    github:​​peewpw/Invoke-PSImage​​简介:EncodesaPowerShellscriptinthepixelsofaPNGfileandgeneratesaonelinertoexecuteInvoke-PSImagetakesaPowerSh......
  • C#中使用Invoke和BeginInvoke跨线程更新UI控件示例代码
    在多线程开发过程中,有时候需要更新UI控件内容,但是在c#多线程Task、Thread、BackgroundWork中不能直接更新UI控件,否则会报调用线程不能访问此对象,因为它由另一个线程拥有The......