我正在尝试将struct作为参数从C#应用程序传递给C ++ MFC DLL。 DLL填充struct对象中的记录并返回C#应用程序。所以我在C#应用程序中使用“out”关键字来调用C ++方法。当我执行它时,它失败并显示错误“尝试读取或写入受保护的内存。这通常表明其他内存已损坏。”我在C ++ DLL中分配内存来存储记录并将其分配给out参数。我可以在struct对象中发送数据并在C ++ DLL中打印它但不能在DLL端对struct对象进行修改并返回C#应用程序。
请有人帮忙解决这个问题。
NativeDLLHelper.cs
class NativeDLLHelper
{
const int FIELD_LENGTH = 255;
[StructLayout(LayoutKind.Sequential)]
public struct APPDATA
{
public int ID;
public int Version;
[MarshalAs(UnmanagedType.LPTStr, SizeConst = FIELD_LENGTH)]
public string AppName;
};
[DllImport("Parser.dll", EntryPoint = "?FillLstStructData@DLLWrapper@@QAEXAAPAU_APPDATA@1@@Z")]
public static extern void FillLstStructData(out APPDATA[] AppDataStruct);
}
Main.cs
NativeDLLHelper.APPDATA[] lstFillAppDataStruct;
NativeDLLHelper.FillLstStructData(out lstFillAppDataStruct);
for (int i = 0; i < lstFillAppDataStruct.Length; i++)
{
Console.WriteLine(" ID[{0:G}]:{1:G}", i, lstFillAppDataStruct[i].ID);
Console.WriteLine(" Version[{0:G}]:{1:G}", i, lstFillAppDataStruct[i].Version);
Console.WriteLine(" AppName[{0:G}]:{1:G}", i, lstFillAppDataStruct[i].AppName);
}
C ++ DLL:
static const int FIELD_LENGTH = 128;
typedef struct _APPDATA
{
int ID;
double Version;
TCHAR AppName[FIELD_LENGTH];
}APPDATA;
extern "C" __declspec(dllexport) FillLstStructData(APPDATA* &pAppData)
{
APPDATA *localAppDataStruct = new APPDATA[2];
localAppDataStruct[0].ID = 1;
localAppDataStruct[0].Version = 1.1;
_tcscpy(localAppDataStruct[0].AppName, L"MS Visual Studio 2010");
localAppDataStruct[1].ID = 2;
localAppDataStruct[1].Version = 2.1;
_tcscpy(localAppDataStruct[1].AppName, L"MS Office 2010");
pAppData = localAppDataStruct;
}
答案 0 :(得分:2)
您导出的函数取消依次为:
void __thiscall DLLWrapper::FillLstStructData(struct DLLWrapper::_APPDATA * &)
这使它成为C ++类的实例方法。你不能对这些方法进行调整,它们需要首先创建C ++对象,而使用pinvoke则无法可靠地执行此操作。只能静态 C ++成员函数。请注意,此函数根本不需要是实例方法,它实际上并不使用类的实例成员。
这不是唯一的问题,还有一个讨厌的内存管理问题。该函数使用:: operator new分配内存,内存需要由调用者释放。但是C#程序不能这样做,它无法访问C ++代码使用的:: operator delete。由于这个原因,这种函数很难从C ++程序中可靠地使用,当你从C#中执行它时它并没有变得更好。正确的方法是允许调用者传递数组。换句话说,APPDATA []和一个额外的参数,表明传递的数组有多长。
如果无法重写此函数,则必须使用C ++ / CLI语言为此类编写包装器。非常重要的是,这个包装器使用与C ++ DLL完全相同的编译器和CRT版本。