我结束了使用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
}
}
我认为你钉了它!然而,“sbyte”是一个C#关键字,所以我必须将其更改为“const char”并且它可以工作。但是,函数得到“无符号字符”(值0到255),我创建了一个System :: String,期望一个有符号的8位整数,这对于ASCII编码有意义,但可能不适用于这种情况(尽管文本I' m接收看起来像普通的ASCII文本)。我希望它不是一些自定义编码。 – tzup 2010-04-30 06:23:32
原来编码是Latin-1,所以这里是更新的行: String^str = gcnew String((const char *)body,0,bodyLen,Encoding :: GetEncoding(“ISO-8859-1”)) – tzup 2010-04-30 09:24:32