所以我在非托管c ++中有一个函数,当某些文本恰好“到达”时会被调用:
#using <MyParser.dll>
...
void dump_body(const unsigned char *Body, int BodyLen)
{
// Need to pass the body to DumpBody, but as what type?
...
MyParser::Parser::DumpBody(???);
}
DumpBody 是一个在C#DLL中定义的静态函数,它应该采用一个类型的参数?
Body 包含长度 BodyLen 的字符数组(文本)。
显然有一些编组需要在这里完成,但我不知道如何。
请帮忙。
答案 0 :(得分:2)
以下代码描述了通过PInvoke在托管C#代码和非托管C / C ++ DLL之间进行通信的情况。基本上这个想法是,您可以将C代码传递给C#委托。 const unsigned char*
转换为带有Marshal.PtrToStringAnsi的string
。
C ++:
typedef void FncFoo (const char*);
FncFoo callback = 0;
extern "C" {
// this function is called from C# to pass the delegate
void TakeFooCallback(FncFoo f) {
callback = f;
}
}
// C function calling C#
void dump_body(const unsigned char *Body, int BodyLen) {
if(callback) {
callback(Body);
}
}
C#:
class StringC2CS {
delegate void DlgFoo(IntPtr a);
[DllImport("myclib.dll")] // name of the dll
void TakeFooCallback(DlgFoo callback);
// this function gets called by C
void FooImpl(IntPtr a) {
string str = Marshal.PtrToStringAnsi(a);
// use string
}
public StringC2CS() {
// passes a callback to C
TakeFooCallback(new DlgFoo(FooImpl));
}
}
答案 1 :(得分:2)
void dump_body(const unsigned char *body, int bodyLen)
{
// you might want a different encoding...
String ^str = gcnew String((sbyte*)body, 0, bodyLen, gcnew ASCIIEncoding);
MyParser::Parser::DumpBody(str);
}
DumpBody将采用字符串。
答案 2 :(得分:0)
我最终使用了Danvil的方法。我将C代码包装在C ++ DLL中,然后我创建了另一个引用C ++ dll的C#dll,并在托管代码中公开了我想要的功能。所以这就是:
C ++ dll:
.h文件
// Definition of a callback function to be called when some data arrives
typedef void (*FncDlg) (const unsigned char*, int len);
// Declaration of the function that will be exposed in managed code.
// The managed code will use this function to pass in a delegate
extern "C" __declspec(dllexport) void AttachCallback(FncDlg f);
// Declaration of a function that receives data and passes it to managed code
void PassData(const unsigned char *Body, int BodyLen);
.cpp文件
// Instantiate a global function pointer to nothing
void (*callback)(const unsigned char*, int len) = 0;
// This is called by C# to pass in a delegate
void AttachCallback(FncDlg f)
{
// Save delegate globally (to be triggered later when we receive data)
callback = f;
}
// This is the function called when data is read from the socket
void PassData(const unsigned char *Body, int BodyLen)
{
if(callback) {
callback(Body, BodyLen);
}
}
C#dll:
public static class Parser
{
public delegate void DlgDumpTipData(IntPtr a, int len);
[DllImport("C++ dll name here", EntryPoint = "AttachCallback", ExactSpelling = true)]
public static extern void AttachCallback(DlgDumpTipData callback);
public static int ConnectAndStartReceive(...)
{
// Attach a callback function (called when a message is received from data feed)
AttachCallback(DumpDataCalback);
...
}
public delegate void MsgHandler(string msg);
// When data arrives from the C library, this event passes it on to C# clients
public static event MsgHandler OnMessageArrived = delegate { };
public static void DumpDataCalback(IntPtr ptr, int len)
{
//string str = Marshal.PtrToStringAnsi(ptr);
string dumpData;
sbyte[] byteArr = new sbyte[len];
for (int i = 0; i < len; i++)
{
// WARNING: if byte > 127 we have a problem when casting from Byte to SByte
// In this case there is no problem, tested with values over 127 and it
// converts fine to Latin-1 using the String overload
byteArr[i] = (sbyte)Marshal.ReadByte(ptr, i);
}
unsafe
{
fixed (sbyte* pbyteArr = byteArr) // Instruct the GC not to move the memory
{
dumpData = new String(pbyteArr, 0, len, Encoding.GetEncoding("ISO-8859-1"));
}
}
// Send data to whoever subscribes to it
OnMessageArrived(dumpData);
GC.Collect(); // This slows things down but keeps the memory usage low
}
}