C#调用C++日志方法 - 记录

要求:托管处调用非托管的log,并显示再TextBox上。

具体做法如下:

【c#部分】

1. 托管端放一个TextBox文本框textBox1,定义一个方法解释传递过来的信息:

        public void ShowMessageToTextBox(object msg)
        {
            this.textBox1.BeginInvoke(new Action(() =>
            {
                this.textBox1.AppendText(msg.ToString() + "\r\n");
            }));
        }

2. 定义一个委托方法:因为只打印log,所以可以使用C#提供的公共委托 public delegate void Action<in T>(T obj);【如果需要带参数可以使用 public delegate TResult Func<out TResult>();】

                private Action<object> m_logAction;                     // Log打印

3. 让委托和TextBox打印函数相关联:

        m_logAction = ShowMessageToTextBox;

4. 定义委托的执行的方法:后面就可以直接调用ShowMessage这个方法进行信息的打印
        /// <summary>
        /// 打印log
        /// </summary>
        /// <param name="Msg">显示的信息</param>
        private void ShowMessage(string Msg)
        {
            if (null == Msg || Msg.Length <= 0)
            {
                return;
            }

            m_logAction?.Invoke(Msg);
        }

【c++部分】

1. 先定义导出函数部分:

/// 定义C++的导出规则:C规则编译指定的代码
#ifdef __cplusplus
extern "C" {
#endif

// 中间写入导出类型、回调函数和其它内容等

/// 结束C++的导出规则定义:C规则编译指定的代码

#ifdef __cplusplus
}    // extern "C"
#endif

2. 宏定义:导出/导入方法:
#ifdef MYDLL_EXPORTS  
        #define AFX_GENIFC_API __declspec(dllexport)  
#else
        #define AFX_GENIFC_API __declspec(dllimport)
#endif

3. 定义函数的入栈出栈字节序: __stdcall 或者 __cdecl ,注意,这里的字节序一定要和C#中的一致,且后面C++的具体实现也需要一致,否则调用很可能崩溃、乱码或者失败
#define MCALL __cdecl 

4. 定义回调函数:
          typedef void(__cdecl* LogCallBack)(const wchar_t* data);

5.     /// <summary>
        ///  注册回调函数:并在CPP中实现
        /// </summary>
        /// <param name="hInstance"> 操作句柄,非必要参数,和C#要对齐 </param>
        /// <param name="LogCallBack">回调参数,必要参数</param>

         AFX_GENIFC_API void MCALL RegistLog_Display_CallBack(void* hInstance, LogCallBack logcb);


AFX_GENIFC_API void MCALL RegistLog_Display_CallBack(void* hInstance, LogCallBack logcb)
{
    CPhone* handle = (CPhone*)hInstance;
    handle->SetLogCallBack(logcb); // 这里才是真正的传log信息回调函数
}

6. 如果是类,需要定义回调的成员变量:
            LogCallBack m_log_cb;

7. 设置log回调函数:
                void CPhone::SetLogCallBack(LogCallBack cb)
                {
                            m_log_cb = cb;
                }

8. 执行C++这边的打印函数:
void CPhone::PrintLog(const char* writeFmt, ...)
{
    USES_CONVERSION;
    if (m_log_cb == NULL)
    {
        return;
    }
    va_list marker;
    va_start( marker, writeFmt );                          // Initialize variable arguments.
    int len = _vscprintf( writeFmt,marker )  + 1;    // _vscprintf doesn't count terminating '\0'
    char* buffer = new char[len];
    SecureZeroMemory(buffer, len);
    vsprintf_s( buffer, len, writeFmt, marker );
    wchar_t* wideChar = A2W(buffer);  /*如果是宽字节,则需要转换成宽字节,否则可以直接输出;这里要注意字节需要和第4步定义回调函数typedef void(__cdecl* LogCallBack)(const wchar_t* data);的参数类型一定要一致*/
    m_log_cb(wideChar);
    delete[] buffer;
    va_end( marker );
}
 

【C#对接接口部分】

1.  对接的回调函数声明:

        /// 注意:C++中定义的MCALL是__stdcall还是__cdecl ,这里CallingConvention一定要对齐;另外,回调函数的参数和返回类型也一定要对齐,不能有任何的偏差:
        [UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl, CharSet = CharSet.Auto)]
        public delegate void LogCallBack(string lpszStr);

2.  定义导出回调
        [DllImport(dllName, EntryPoint = "RegistLog_Display_CallBack", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
        public static extern bool RegistLog_Display_CallBack(IntPtr pHandle, LogCallBack cb);

【使用】

在类中可以这样使用:

1. 定义回调:        LogCallBack cb;

2. 绑定回调:        cb += ShowMessage; // ShowMessage是前面的C#定义,采用m_logAction委托执行函数。

3. 注册回调:        RegistLog_Display_CallBack(Handle, cb);

4. 回调保持激活状态:GC.KeepAlive(cb); // 这个一定要加上,否则可能定义一个局部变量被垃圾回收后导致回调异常

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值