这几天又开始了用 c#写窗口程序,自认为用c#做窗口程序太简单了,比那什么mfc简单太多,当然可能QT等库也是比较简单,我就懒得去学习了。
//[return: MarshalAs(UnmanagedType.LPStr)]
//[MarshalAs(UnmanagedType.LPStr)]
废话短说,我做一个服务器测试程序,也只有跟用户交互的部分是使用的c#窗口,其他都是c++ dll。
然后肯定会出现c#调用c++的问题,这个很容易解决,c#代码的写法如下:
[DllImport("TestCommand.dll", EntryPoint = "StartRun", CallingConvention=CallingConvention.StdCall)]
public static extern int StartRun(string ip, UInt16 port, StringBuilder out_err_msg, int msg_buffer_length);
[DllImport("TestCommand.dll", EntryPoint = "Register", CallingConvention=CallingConvention.StdCall)]
public static extern int Register(string name_or_tel, string pwd, int reg_type, StringBuilder out_err_msg, int msg_buffer_length);
那么c# 如何调用:
private void RunNetIO(string ip, UInt16 port)
{
ThreadSynUIFunc ui_func = new ThreadSynUIFunc(ThreadSynUIFuncImpl);
this.Invoke(ui_func, new object[] { eUIControl._register, false });
StringBuilder out_err_msg = new StringBuilder(512);
int ret_val = ImCommand.StartRun(ip, port, out_err_msg, 512);
if(ret_val != Common.RET_INT_OK)
{
MessageBox.Show(out_err_msg.ToString());
}
this.Invoke(ui_func, new object[] { eUIControl._register, true });
}
private void ThreadSynUIFuncImpl(eUIControl ui, bool enabled)
{
switch(ui)
{
case eUIControl._register:
bt_connect.Enabled = enabled;
break;
}
}
private void button_register_Click(object sender, EventArgs e)
{
int reg_type = Convert.ToInt32(rb_name.Tag);
if (rb_tel.Checked) { reg_type = Convert.ToInt32(rb_tel.Tag); }
StringBuilder out_err_msg = new StringBuilder(512);
int ret_val = ImCommand.Register(tb_name_tel.Text, tb_pwd.Text, reg_type, out_err_msg, 512);
if (ret_val != Common.RET_INT_OK)
{
MessageBox.Show(out_err_msg.ToString());
}
}
}
cpp的写法:
int AssignReturnVal(char* d, int d_len, const char* s, int return_val)
{
int s_len = strlen(s);
if (s_len > d_len)
{
s_len = d_len;
}
strncpy_s(d, d_len, s, s_len);
return return_val;
};
template
int ExecImpl(Func func, char* out_err_msg, int in_msg_buffer_length, Args... args)
{
try{ func(args...); }
catch (const char* ex){ return AssignReturnVal(out_err_msg, in_msg_buffer_length, ex, RET_INT_FAIL); }
catch (std::exception ex){ return AssignReturnVal(out_err_msg, in_msg_buffer_length, ex.what(), RET_INT_FAIL); }
return AssignReturnVal(out_err_msg, in_msg_buffer_length, RET_STR_OK, RET_INT_OK);
}
extern "C"
{
TESTCOMMAND_API int __stdcall StartRun(const char* ip,
uint16_t port, char* out_err_msg, int in_msg_buffer_length)
{
if (!ip || strlen(ip) == 0 || port <= 1000)
{
AssignReturnVal(out_err_msg, in_msg_buffer_length, "ip or port invalid.", RET_INT_FAIL);
}
return ExecImpl(std::bind(&BoostNet::Run, &BOOSTNET, ip, port), out_err_msg, in_msg_buffer_length);
}
TESTCOMMAND_API int __stdcall Register(const char* name_or_tel,
const char* pwd, int reg_type, char* out_err_msg, int in_msg_buffer_length)
{
return ExecImpl(NetCommand::Register, out_err_msg, in_msg_buffer_length, name_or_tel, pwd, reg_type);
}
}
就这样没什么难度,那么如果c++要调用c#函数呢,比如来消息了,c++网络层总要通知c#窗口吧。
比如c++想要传递给c#:
typedef void (__stdcall *FUNC_ARGC_3)(uint64_t msg_id, const char* title, const char* des);
FUNC_ARGC_3 _g_func_3 = nullptr;
那么,c++该怎么写,c# 该怎么写?
ok,下面展示2个例子,不但是供我以后参考,也希望帮助些朋友。
第一部分:
------------------------------------------------
cpp文件:
typedef void (__stdcall *FUNC_ARGC_3)(uint64_t msg_id, const char* title, const char* des);
FUNC_ARGC_3 _g_func_3 = nullptr;
extern "C"
{
TESTCOMMAND_API void __stdcall SetCallBackFunc(void* func, int argc)
{
switch (argc)
{
case 3:
_g_func_3 = (FUNC_ARGC_3)func;
return;
}
}
}
h文件:
extern "C"
{
//typedef void(*FUNC_ARGC_3)(uint64_t msg_id, const char* title, const char* des);
TESTCOMMAND_API void __stdcall SetCallBackFunc(void* func, int argc);
}
关键部分,c#:
//typedef void(*FUNC_SENDFAIL_CALLBACK)(int);
public delegate void FUNC_SET_CALLBACK_SENDFAIL(int proto_id);
[DllImport("TestCommand.dll", EntryPoint = "SetSendFailedCallbackFunc", CallingConvention = CallingConvention.StdCall)]
public static extern void SetSendFailedCallbackFunc(FUNC_SET_CALLBACK_SENDFAIL func);
//typedef void(*FUNC_ARGC_3)(uint64_t msg_id, const char* title, const char* des);
public delegate void FUNC_SET_CALLBACK_3(UInt64 msg_id, string title, string des);
[DllImport("TestCommand.dll", EntryPoint = "SetCallBackFunc", CallingConvention = CallingConvention.StdCall)]
public static extern void SetCallBackFunc_3(FUNC_SET_CALLBACK_3 func, int argc);
public Form1()
{
InitializeComponent();
ImCommand.SetSendFailedCallbackFunc(new ImCommand.FUNC_SET_CALLBACK_SENDFAIL(Callback_sendfail));
ImCommand.SetCallBackFunc_3(new ImCommand.FUNC_SET_CALLBACK_3(Callback_argc_3), 3);
}
private void Callback_sendfail(int proto_id)
{
MessageBox.Show(string.Format("send msg[{0}] fail.", proto_id));
}
private void Callback_argc_3(UInt64 msg_id, string title, string des)
{
MessageBox.Show(string.Format("[{0}:{1}]", msg_id, des), title);
}
注意:或许你可能发现,c#多了一部分代码,多的那一部分对应的c++代码将在下面展示,下面第二部分就不在展示c#代码了!!! 请各就各位。
第二部分的c++代码:
-----------------------------------------------
h:
extern "C"
{
//typedef void(*FUNC_SENDFAIL_CALLBACK)(int);
TESTCOMMAND_API void __stdcall SetSendFailedCallbackFunc(void* func);
}
cpp:
typedef void(__stdcall *FUNC_SENDFAIL_CALLBACK)(int);
FUNC_SENDFAIL_CALLBACK _g_func_send_fail_callback = nullptr;
extern "C"
{
TESTCOMMAND_API void __stdcall SetSendFailedCallbackFunc(void* func)
{
_g_func_send_fail_callback = (FUNC_SENDFAIL_CALLBACK)func;
}
}
ok,希望 我的废话不多,能给朋友一些直接参考!
---------------------
作者:oiooooio
来源:CSDN
原文:https://blog.csdn.net/oiooooio/article/details/48368329
版权声明:本文为博主原创文章,转载请附上博文链接!