C++DLL到C#错误:“;尝试读取或写入受保护的内存.这通常表示其他内存已损坏&”;
本文关键字:内存 常表示 表示 已损坏 其他 受保护 错误 读取 C++DLL | 更新日期: 2023-09-27 18:22:33
我有两个DLL。一个是PrimaryDLL.dll,另一个是DLLLrap.dll。PrimaryDLL有一个对象,一个名为DiversifyKeyset的函数,在类构造函数中标记为:
static PRIMARYDLL_API std::string DiversifyKeyset(std::string Key1, std::string Key2, std::string Key3);
这里是定义的方法:
std::string tKeyset::DiversifyKeyset(std::string Key1, std::string Key2, std::string Key3)
{
tKeyset* keyset = new tKeyset();
keyset ->Key1 = "12345678";
keyset ->Key2 = "23456789";
keyset ->Key3 = "34567890";
//return keyset --eventually I want to return this
return 0;
}
我的DLLLrap.dll在其.cpp文件中这样调用此函数:
cout << "Here is what is returned: " <<
firstDllLayer::tKeyset::DiversifyKeyset(a,b,c) << endl;
现在,所有这些都编译得很好,库也构建好了。当我调用C#代码来调用第二个DLLLrap.dll时,我出现了错误。我收到了错误:
Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
因此,我一直在绞尽脑汁,想为什么这不起作用。我承受着很大的压力,但似乎不明白为什么我会收到这个记忆写入错误。
因此,为了帮助我提供我的代码。
我的C++PrimaryDLL.h文件:
#pragma once
#include "stdafx.h"
#include <string>
#include <stdexcept>
extern "C"{
#ifdef PRIMARYDLL_EXPORT
#define PRIMARYDLL_API __declspec(dllexport)
#else
#define PRIMARYDLL_API __declspec(dllimport)
#endif
namespace firstDllLayer
{
class tKeyset
{
public:
tKeyset();
std::string Key1;
std::string Key2;
std::string Key3;
tKeyset(std::string _key1, std::string _key2, std::string _key3);
static PRIMARYDLL_API std::string DiversifyKeyset(std::string Key1, std::string Key2, std::string Key3);
};
tKeyset::tKeyset()
{
Key1 = "";
Key2 = "";
Key3 = "";
}
tKeyset::tKeyset(std::string _Key1, std::string _Key2, std::string _Key3)
{
Key1 = _Key1;
Key2 = _Key2;
Key3 = _Key3;
}
}
}
这是PrimaryDll.cpp文件:
// PrimaryDll.cpp : Defines the exported functions for the DLL application.
//
#include "stdafx.h"
#include "PrimaryDll.h"
#include <stdexcept>
#include <string>
using namespace std;
namespace firstDllLayer
{
tKeyset* MasterKeyset = new tKeyset("1234","5678","0910");
std::string tKeyset::DiversifyKeyset(std::string Key1, std::string Key2, std::string Key3)
{
tKeyset* keyset = new tKeyset();
keyset ->Key1 = "12345678";
keyset ->Key2 = "23456789";
keyset ->Key3 = "34567890";
//return Keyset; -eventually I would like to return this
return 0;
}
}
这是我的DLLWrap.h文件:
#pragma once
#include "stdafx.h"
#include "Primary.h"
#include <stdexcept>
#include <string>
extern "C"{
#ifdef DLLWRAPDLL_EXPORT
#define DLLWRAP_API __declspec(dllexport)
#else
#define DLLWRAP_API __declspec(dllimport)
#endif
namespace MyFunc
{
class MyCall
{
public:
static DLLWRAP_API std::string DiversifyKeysetCall(std::string a,std::string b,std::string c);
};
}
}
DLLFrap.pp文件:
// DLLWrap.cpp : Defines the exported functions for the DLL application.
//
#include "stdafx.h"
#include "PrimaryDll.h"
#include <stdexcept>
#include "DLLWrap.h"
#include <iostream>
#include <string>
using namespace std;
namespace MyFunc
{
std::string MyCall::DiversifyKeysetCall(std::string a,std::string b,std::string c)
{
/*cout << "Here is what is returned: " <<
firstDllLayer::tKeyset::DiversifyKeyset(a,b,c) << endl;
return 0;*/
cout << "Here is what is returned: " <<
firstDllLayer::tKeyset::DiversifyKeyset(a,b,c) << endl;
return 0;
}
}
最后是C#程序.cs文件:
// Marshal.cs
using System;
using System.Runtime.InteropServices;
class PlatformInvokeTest
{ public class DllHelper
{
[DllImport(@"C:'Users'user'Documents'Visual Studio 2010'Projects'KeyDll'Debug'DLLWrap.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "?DiversifyKeysetCall@MyCall@MyFunc@@SA?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@V34@00@Z")]
public static extern string DiversifyKeysetCall(string a, string b, string c);
}
static void Main()
{
try
{
DllHelper.DiversifyKeysetCall("1234","5678","0910");
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}
在我的PrimaryDLL.cpp文件中,我最终想返回对象,但因为它在如何引用指针以及何时离开:方面太令人困惑了
return keyset;
Uncomment我收到错误,它无法从对象类型转换为字符串类型。
因此,如果有任何帮助,我将非常感谢为什么我收到"试图读取或写入受保护的内存。这通常表明其他内存已损坏"错误。
谨致问候。
在c++dll中创建一个对象并将其交回c#通常是个坏主意。内存的所有权成为一个问题。字符串是可以的,因为它们通过从c内存处理到c拥有的内存来进行编组。
我建议您通过分别传递这三个字符串并在c#中构建您的密钥集对象来简化整个过程。
另一种选择是将键集对象展平为字节的二进制数组。然后,当你把它拿回来时,有一个自定义的函数,可以把它取消填充到一个对象中。
以下是我在之前所做的
[DllImport("Helper.dll", CharSet = CharSet.Auto)]
private static extern bool GetStuff(
[MarshalAs(UnmanagedType.LPStr)] StringBuilder inputString,
byte[] outputBuffer,
UInt32 outputSize,
ref UInt32 outputFinalSize);
public static void DoStuff(string inputString)
{
int buffSize = 4000;
byte[] buff = new byte[buffSize];
StringBuilder inputString = new StringBuilder();
inputString.Append(blobs);
UInt32 size = 0;
if (!GetStuff(inputString, buff, (uint)buffSize, ref size) || size == 0)
{
//ERROR
}
when it comes back i just do
StringBuilder outputString;
for (uint i = 0; i < outputFinalSize; i++)
{
outputString.Append((char)buff[i]);
}
outputString.toString();
}
c信号看起来像这个
extern "C" __declspec(dllexport) bool GetStuff(char* inputString, char* outputBuffer, UInt32 outputSize, UInt32& outputFinalSize);
请注意,我也使用字符串生成器来传递字符串,您可能不需要。。。正如你所看到的,我在c#端分配所有东西,这样我就不必担心c++的内存管理,当函数完成时,c++中的所有东西都应该被释放。
你的电话看起来应该有点像
private static extern bool DiversifyKeysetCallAndRetrunFlatBuffer(
[MarshalAs(UnmanagedType.LPStr)] StringBuilder inputStringA,
[MarshalAs(UnmanagedType.LPStr)] StringBuilder inputStringB,
[MarshalAs(UnmanagedType.LPStr)] StringBuilder inputStringC,
byte[] outputBuffer,
UInt32 outputSize,
ref UInt32 outputFinalSize);
{
std::string str1(inputStringA);
std::string str2(inputStringB);
std::string str3(inputStringC);
KeySet key = DiversifyKeyset(str1, str2, str3);
outputFinalSize = key.SerializeToBuffer(outputBuffer, outputSize);
if (outputFinalSize == 0)
{
return false;
}
return true;
}
int KeySet::SerializeToBuffer(char* buffer, size_t bufferSize)
{
//We are going to fill the buffer like so "key1|key2|key3"
size_t totalSize = Key1.size() + Key2.size() + Key3.size() + 4;
if (bufferSize < totalSize)
{
return 0; // buffer too small
}
char* bufferCurr = buffer;
memcpy(bufferCurr, Key1.c_str(), Key1.size());
bufferCurr += Key1.size();
bufferCurr[0] = '|';
bufferCurr++;
memcpy(bufferCurr, Key2.c_str(), Key2.size());
bufferCurr += Key2.size();
bufferCurr[0] = '|';
bufferCurr++;
memcpy(bufferCurr, Key3.c_str(), Key3.size());
bufferCurr += Key3.size();
bufferCurr[0] = ''0';
return totalSize;
}
最后,在c#端,您可以将缓冲区转换为字符串,并通过|进行拆分以获得所有3个键,然后创建一个包含3个字符串的c#键集对象。
std::string tKeyset::DiversifyKeyset(...) { return 0; }
这调用std::string(const char*)构造函数,传递一个NULL指针。这是违法的。