C# DLL中CARR*的结构值从C++到C节(编组/ pJoCKE) 我现在有一个DLL,它有一个结构,我声明它将被C和C++应用程序用来存储内存映射文件中的信息。 #pragma pack(1) typedef struct SHAREDMEMORY_API Data { public: int getKind() { return kind; } int getCountry() { return country; } int getExtra() { return extra; } char* getName(){ printf("Get name value in struct: %s\n", name); return name; } void setKind(int sKind) { kind = sKind; } void setCountry(int scountry) { country = scountry; } void setName(char* sname){ name = new char[strlen(sname)]; strcpy(name, sname); } void deletePointer(){ delete[] name; delete[] type; delete[] band; } private: int kind; int country; int extra; char* name; }; 这些是我在DLL中暴露的方法,以便我的C++ exe和cexe可以调用.< /p> extern "C" void SetData( int kind, int country, int extra, char* name) { CMutex mutex; int size = 1; Data* dynamicArray = new Data[size]; if(m_pViewMMFFile) { Data* record = (Data*) m_pViewMMFFile; // Maps the memory mapped file as an Data object array for (int i = 0; i < size; i++) { dynamicArray[i].setKind(kind); printf("setKind: %i\n", kind); dynamicArray[i].setCountry(country); printf("setCountry: %i\n", country); dynamicArray[i].setExtra(extra); printf("setExtra: %i\n", extra); dynamicArray[i].setName(name); printf("setName: %s\n", name); record[i] = dynamicArray[i]; } record = dynamicArray; delete[] dynamicArray; } mutex.~CMutex(); }
这就是我试图用C语言进行编组的地方C# DLL中CARR*的结构值从C++到C节(编组/ pJoCKE) 我现在有一个DLL,它有一个结构,我声明它将被C和C++应用程序用来存储内存映射文件中的信息。 #pragma pack(1) typedef struct SHAREDMEMORY_API Data { public: int getKind() { return kind; } int getCountry() { return country; } int getExtra() { return extra; } char* getName(){ printf("Get name value in struct: %s\n", name); return name; } void setKind(int sKind) { kind = sKind; } void setCountry(int scountry) { country = scountry; } void setName(char* sname){ name = new char[strlen(sname)]; strcpy(name, sname); } void deletePointer(){ delete[] name; delete[] type; delete[] band; } private: int kind; int country; int extra; char* name; }; 这些是我在DLL中暴露的方法,以便我的C++ exe和cexe可以调用.< /p> extern "C" void SetData( int kind, int country, int extra, char* name) { CMutex mutex; int size = 1; Data* dynamicArray = new Data[size]; if(m_pViewMMFFile) { Data* record = (Data*) m_pViewMMFFile; // Maps the memory mapped file as an Data object array for (int i = 0; i < size; i++) { dynamicArray[i].setKind(kind); printf("setKind: %i\n", kind); dynamicArray[i].setCountry(country); printf("setCountry: %i\n", country); dynamicArray[i].setExtra(extra); printf("setExtra: %i\n", extra); dynamicArray[i].setName(name); printf("setName: %s\n", name); record[i] = dynamicArray[i]; } record = dynamicArray; delete[] dynamicArray; } mutex.~CMutex(); },c#,c++,dll,pinvoke,marshalling,C#,C++,Dll,Pinvoke,Marshalling,这就是我试图用C语言进行编组的地方 class Program { [DllImport("MemoryMapDLL.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] extern static void SetData( [MarshalAs(UnmanagedType.I4)] int kind, [MarshalAs(UnmanagedTyp
class Program
{
[DllImport("MemoryMapDLL.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
extern static void SetData(
[MarshalAs(UnmanagedType.I4)] int kind,
[MarshalAs(UnmanagedType.I4)] int country,
[MarshalAs(UnmanagedType.I4)] int extra,
[MarshalAs(UnmanagedType.LPStr)] string name
);
[DllImport("MemoryMapDLL.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
extern static IntPtr GetData();
private void UdpMessageSending(string inputMessage)
{
UdpClient udpClient = new UdpClient(11000);
udpClient.Connect("127.0.0.1", 11000);
Console.WriteLine("Sending UDP Message: " + inputMessage);
// Sends a message to the host to which you have connected.
Byte[] sendBytes = Encoding.ASCII.GetBytes(inputMessage);
udpClient.Send(sendBytes, sendBytes.Length);
udpClient.Close();
}
static void Main(string[] args)
{
try
{
for (; ;)
{
string x = Console.ReadLine();
Program p = new Program();
p.UdpMessageSending("Play");
//SetData(1, 2, 225, 2, type, 4, 1, 0, name, 1, 4, band);
Thread.Sleep(1000);
IntPtr ptr = GetData();
Console.WriteLine("Pointer: " + ptr.ToString());
MarshalClass.Data data = (MarshalClass.Data)Marshal.PtrToStructure(ptr, typeof(MarshalClass.Data));
Console.WriteLine("Data Size in C#: " + Marshal.SizeOf(typeof(MarshalClass.Data)));
Console.WriteLine("Kind: " + data.kind);
Console.WriteLine("Country: " + data.country);
Console.WriteLine("Extra: " + data.extra);
IntPtr nameIntPtr = data.name;
Console.WriteLine("NameIntPtr: " + nameIntPtr);
string name = Marshal.PtrToStringAnsi(nameIntPtr);
if (name != null)
{
Console.WriteLine("Name: " + name);
}
}
}
catch (Exception exception)
{
Console.WriteLine("Error");
Console.WriteLine("===============================================");
Console.WriteLine(exception.ToString());
}
}
}
}
当我试图检索C端的信息时,问题出现了。它无法检索char*name属性。当它试图调用DLL中的GetData方法时,会抛出AccessViolationException错误并使我的应用程序崩溃,这就是这种情况。但是,它能够检索整数类型的其他属性,没有任何问题。如果我试图在C和C中设置数据,那么它会完全恢复,但当我的C++应用程序试图检索char *名称时,应用程序就会崩溃。然而,在我的DLL中,我能够打印出存储的名称数据的地址,因此消除了它为空的可能性。那么,可能的原因是什么呢?有人知道解决这个问题的方法吗?这是从一个大错误开始的,setName函数有一个off by one错误。它必须分配strlensname+1字节,为零终止符额外分配一个字节。这导致的堆损坏只会让程序陷入无法察觉的痛苦漩涡,当您使用pinvoke时,调试难度会增加十倍。无法可靠地释放分配给数据的内存只会让情况变得更糟。我已经对代码进行了重大更改,采纳了您给出的建议,我使用固定大小的字符数组而不是字符指针,现在工作正常。谢谢你的评论!
using System;
using System.Collections.Generic;
class MarshalClass
{
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public class Data
{
public Int32 kind;
public Int32 country;
public Int32 extra;
public IntPtr name;
}
}
}
class Program
{
[DllImport("MemoryMapDLL.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
extern static void SetData(
[MarshalAs(UnmanagedType.I4)] int kind,
[MarshalAs(UnmanagedType.I4)] int country,
[MarshalAs(UnmanagedType.I4)] int extra,
[MarshalAs(UnmanagedType.LPStr)] string name
);
[DllImport("MemoryMapDLL.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
extern static IntPtr GetData();
private void UdpMessageSending(string inputMessage)
{
UdpClient udpClient = new UdpClient(11000);
udpClient.Connect("127.0.0.1", 11000);
Console.WriteLine("Sending UDP Message: " + inputMessage);
// Sends a message to the host to which you have connected.
Byte[] sendBytes = Encoding.ASCII.GetBytes(inputMessage);
udpClient.Send(sendBytes, sendBytes.Length);
udpClient.Close();
}
static void Main(string[] args)
{
try
{
for (; ;)
{
string x = Console.ReadLine();
Program p = new Program();
p.UdpMessageSending("Play");
//SetData(1, 2, 225, 2, type, 4, 1, 0, name, 1, 4, band);
Thread.Sleep(1000);
IntPtr ptr = GetData();
Console.WriteLine("Pointer: " + ptr.ToString());
MarshalClass.Data data = (MarshalClass.Data)Marshal.PtrToStructure(ptr, typeof(MarshalClass.Data));
Console.WriteLine("Data Size in C#: " + Marshal.SizeOf(typeof(MarshalClass.Data)));
Console.WriteLine("Kind: " + data.kind);
Console.WriteLine("Country: " + data.country);
Console.WriteLine("Extra: " + data.extra);
IntPtr nameIntPtr = data.name;
Console.WriteLine("NameIntPtr: " + nameIntPtr);
string name = Marshal.PtrToStringAnsi(nameIntPtr);
if (name != null)
{
Console.WriteLine("Name: " + name);
}
}
}
catch (Exception exception)
{
Console.WriteLine("Error");
Console.WriteLine("===============================================");
Console.WriteLine(exception.ToString());
}
}
}