在 /MT 或 /MD 上 P/调用“受保护的内存”异常

Posted

技术标签:

【中文标题】在 /MT 或 /MD 上 P/调用“受保护的内存”异常【英文标题】:P/Invoke "Protected Memory" exception on /MT or /MD 【发布时间】:2015-12-15 20:06:39 【问题描述】:

我为 CryptoPP 编写了一个包装器,供 c# 应用程序使用。 我的问题是,当使用 PInvoke 调用包装器中的特定函数时,会引发异常“尝试读取或写入受保护的内存......”。 它们都编译为 x64。

现在.. 奇怪的是 如果我使用 /MTd 或 /MDd 运行时编译我的包装器,调用不会失败并且一切正常。 但是将运行时更改为 /MT 或 /MD会抛出上述异常。

我不能将 /MTd 或 /MDd 选项用于我的客户正式使用,因为它需要安装或分发大量 dll 资源到用户计算机中。

cpp代码:

extern "C" __declspec(dllexport) int CryptBlock(bool mode, unsigned char type, unsigned char *inData, unsigned char *outData, int dataLen, unsigned char *key, int keyLen);

c#PInvoke:

[DllImport("mydll.dll", SetLastError = true, CallingConvention = CallingConvention.Cdecl)]
    public static extern int CryptBlock(bool mode, byte type, IntPtr inData, IntPtr outData, int dataLen, IntPtr key, int keyLen);

我尝试以各种方式修改我的 P/Invoke 代码: [In, Out], [Out], ref, ref byte[], byte[] 等等...仍然抛出异常。

等待我的救命恩人……

谢谢。

【问题讨论】:

可能是您的 CryptBlock 代码中的某个错误,仅在不使用 /MTd 或 /MDd 时才会触发:这些是调试库,与释放模式相比,内存可能以不同的方式初始化(IIRC 调试 crt 库倾向于在调试时将内存初始化为全 0,但在发布时不会,因此假设您有一个未初始化的变量,然后使用它来索引数组 - BAM)。也许启用所有运行时检查会揭示问题,另见例如***.com/questions/186237/… 你怎么打电话给CryptBlock()?可能您的dataLenkeyLen 是错误的。 【参考方案1】:

你是对的,你不能分发调试运行时,但实际上问题并不像你想的那样。该许可证不允许重新分发调试运行时。

最可能的解释实际上是您的代码存在缺陷。调试运行时未显示该缺陷的事实完全取决于机会。所以正确的方法是追踪你的缺陷并修复它。

【讨论】:

【参考方案2】:

考虑在托管代码和非托管代码之间架起一座桥梁。 调试起来更方便...

例子:

C++ 非托管代码:

class ExampleCpp

private:

    int id;

public:

    ExampleCpp();
    ~ExampleCpp();

    const int getId();

;    

C++ 托管代码:

public ref class ExampleManagedCpp

private:
    ExampleCpp* pImpl;

public:

    ExampleManagedCpp();
    ~ExampleManagedCpp();
    !ExampleManagedCpp();
;

http://www.codeproject.com/Articles/868230/Cplusplus-CLI-Accessing-a-managed-type-from-unmana

http://blogs.msdn.com/b/soultech/archive/2010/07/27/cli-c_2b002b00_-to-c_2300_-hello-world.aspx

【讨论】:

以上是关于在 /MT 或 /MD 上 P/调用“受保护的内存”异常的主要内容,如果未能解决你的问题,请参考以下文章

ArcEngine尝试读取或写入受保护的内存

尝试读取或写入受保护的内存

PInvoke - 读取字符串字段的值 - “尝试读取或写入受保护的内存”

c#调用DELPHI的DLL出现“尝试读取或写入受保护的内存。这通常指示其他内存已损坏 请问在c#中怎么调用

尝试读取或写入受保护的内存

示尝试读取或写入受保护的内存 这通常指示其它内存已损坏