一、关于非托管C++调用C# DLL的问题:
1.可以在二者之间增加一个桥梁,使用C++/CLI(取代了托管C++) ,原生C++代码为主调程序,C++/CLI和C#/.NET 均为动态库*.dll。
2.原生C++可以使用函数LoadLibrary(dllFileName)加载dll,然后使用函数GetProcAddress()调用C++/CLI里的接口函数
代码片段:
BOOL dealDll(MachineConf2 &dllMachine)
{
BOOL bolRet = FALSE;
DLLInfo *dllInfoTmp;
CString inDllFileName;
char cTmp[1024];
LOG4CXX_TRACE(logger_, "dealDll start...");
inDllFileName = dllMachine.dllFileName;
if (inDllFileName.GetLength() > 0)
{
dllInfoTmp = &(dllStruct.dllInfo[dllStruct.iDllCount]);
if (!PathFileExists(inDllFileName.GetBuffer()))
{
sprintf(cTmp, "dealDll, dllFileName dosn't exist, dllFileName =[%s]", inDllFileName.GetBuffer());
inDllFileName.ReleaseBuffer();
LOG4CXX_WARN(logger_, cTmp);
return bolRet;
}
else
{
inDllFileName.ReleaseBuffer();
for(int i = 0; i< dllStruct.iDllCount; i++)
{
if (dllStruct.dllInfo[i].dllFilename == inDllFileName)
{
dllMachine.dllIndex = i;
return TRUE;
}
}
}
dllInfoTmp->dllFilename = inDllFileName;
dllInfoTmp->pHModule = LoadLibrary(inDllFileName);
if (NULL == dllInfoTmp->pHModule)
{
sprintf(cTmp, "dealDll, load dll fail, dllFileName =[%s]", inDllFileName.GetBuffer());
inDllFileName.ReleaseBuffer();
LOG4CXX_WARN(logger_, cTmp);
return bolRet;
}
dllInfoTmp->funInital = (FunInital)GetProcAddress(dllInfoTmp->pHModule, "initalMachine");
if (NULL == dllInfoTmp->funInital)
{
sprintf(cTmp, "dealDll, get function initalMachine fail, dllFileName =[%s]", inDllFileName.GetBuffer());
inDllFileName.ReleaseBuffer();
LOG4CXX_WARN(logger_, cTmp);
return bolRet;
}
dllInfoTmp->funFree = (FunFree)GetProcAddress(dllInfoTmp->pHModule, "freeMachine");
if (NULL == dllInfoTmp->funFree)
{
sprintf(cTmp, "dealDll, get function freeMachine fail, dllFileName =[%s]", inDllFileName.GetBuffer());
inDllFileName.ReleaseBuffer();
LOG4CXX_WARN(logger_, cTmp);
return bolRet;
}
dllInfoTmp->setCallBackfun = (SetCallBackFun)GetProcAddress(dllInfoTmp->pHModule, "SetDataCallBackFun");
if (NULL == dllInfoTmp->setCallBackfun)
{
sprintf(cTmp, "dealDll, get function SetDataCallBackFun fail, dllFileName =[%s]", inDllFileName.GetBuffer());
inDllFileName.ReleaseBuffer();
LOG4CXX_WARN(logger_, cTmp);
return bolRet;
}
//ADD set callbackfun
dllInfoTmp->setCallBackfun(CallbackDataQueue);
dllMachine.dllIndex = dllStruct.iDllCount;
dllStruct.iDllCount++;
bolRet = TRUE;
}
else
{
LOG4CXX_WARN(logger_, "dealDll, input dllFileName is NULL!");
return bolRet;
}
LOG4CXX_TRACE(logger_, "dealDll End...");
return bolRet;
}
二、关于C++与C#数据交互&C#/.NET与C++/CLI函数互调:
C#调C++
C++
adapter.h
#ifndef O_U_Adapter_H_
#define O_U_Adapter_H_
#include <windows.h>
#include <iostream>
#include <stdio.h>
#include <time.h>
//此方式为使用经典C方式生成动态库
#ifdef _EXPORTING
#define API_DECLSPEC extern "C" _declspec(dllexport)
#else
#define API_DECLSPEC extern "C" _declspec(dllimport)
#endif
API_DECLSPEC void DataTransferGate(char* str);
API_DECLSPEC void AlarmTransferGate(char* str);
API_DECLSPEC char* GetXmlAddress();
API_DECLSPEC char* GetElementNode();
API_DECLSPEC int GetPublishingInterval();
API_DECLSPEC char* GetMachineIP();
API_DECLSPEC int GetPublishingBehaviour();
//测试
API_DECLSPEC int Connect();
#endif//O_U_Adapter_H_
adapter.cpp
void DataTransferGate(char *str)
{
std::cout << "Data GATE Start " << std::endl;
string json = str;
//WriteLog("0.txt", str);
if (sData.size() < QUEUE_MAXSIZE)
{
sData.push(json);
}
else
{
while (!sData.empty())
sData.pop();
}
}
int GetPublishingInterval()
{
return atoi((char*)pSTRUCT.machine.collCycle.data());
}
char* GetMachineIP()
{
return (char*)pSTRUCT.machine.machineIp.data();
}
C#
public class DllImport
{
[DllImport("O.U.Adapter.dll", EntryPoint = "DataTransferGate", SetLastError = true, CharSet = CharSet.Unicode, ExactSpelling = false, CallingConvention = CallingConvention.Cdecl)]
public static extern void DataTransfer([MarshalAs(UnmanagedType.LPStr)]string str);
[DllImport("O.U.Adapter.dll", EntryPoint = "AlarmTransferGate", SetLastError = true, CharSet = CharSet.Unicode, ExactSpelling = false, CallingConvention = CallingConvention.Cdecl)]
public static extern void AlarmTransfer([MarshalAs(UnmanagedType.LPStr)]string str);
[DllImport("O.U.Adapter.dll", EntryPoint = "GetPublishingInterval")]
public static extern int GetPublishingInterval();
[DllImport("O.U.Adapter.dll", EntryPoint = "GetMachineIP")]
public static extern IntPtr GetMachineIPByBytes();
}
C++调C#
C++
using namespace O::U::Application;
#ifdef _DEBUG
#using "O.U.Application.dll"
#else
#using "O.U.Application.dll"
#endif // _DEBUG
int Connect()
{
int stopTimeout = -1;//Timeout.Infinite;
System::String^ endpointURL;
bool userAuth = false;
// TODO: 读取配置文件信息。
//pSTRUCT.machine.machineIp = "127.0.0.1";
//pSTRUCT.machine.machinePort = "51210";
endpointURL = gcnew String(pSTRUCT.machine.machineIp.c_str()) + ":" + gcnew String(pSTRUCT.machine.machinePort.c_str());
userAuth = (pSTRUCT.machine.userName != "" &&
pSTRUCT.machine.password != "") ? true : false;//条件成立赋值true,条件不成立赋值false
System::String^ userName = gcnew String(pSTRUCT.machine.userName.c_str());//"Client";
System::String^ password = gcnew String(pSTRUCT.machine.password.c_str());//"SUNRISE";
Log4netWrapper ^logger;
logger->Instance->InfoFormat("userName:{0},password:{1}", userName, password);
OUClient ^client;
if (userAuth)
{
client = gcnew Client(endpointURL, stopTimeout, userName, password);
}
else
{
client = gcnew Client(endpointURL, stopTimeout);
}
client->Run();
return (int)Client::ExitCode;
}
基本数据类型转换:
三、关于回调
回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。
#include <stdio.h>
typedef int(*callback)(int,int);
int add(int a,int b,callback p){
//特定的事件或条件发生时,调用者使用函数指针调用回调函数
return (*p)(a,b);
}
int add(int a,int b){
return a+b;
}
int main(int argc,char *args[]){
//将函数的地址注册给调用者
int res = add(4,2,add);
printf("%d\n",res);
return 0;
}
参考:
https://blog.csdn.net/wangweitingaabbcc/article/details/7663949
https://blog.csdn.net/yanlinembed/article/details/78920276
https://blog.csdn.net/AGroupOfRuffian/article/details/78530094