在 c# System.AccessViolationException 处导出 c++ 函数和使用函数

Posted

技术标签:

【中文标题】在 c# System.AccessViolationException 处导出 c++ 函数和使用函数【英文标题】:Exporting c++ functions and use functions at c# System.AccessViolationException 【发布时间】:2019-12-19 13:03:17 【问题描述】:

您好,我尝试从 c++ 导出函数并尝试在 c# 中运行它,但我收到一个错误 System.AccessViolationException: An attempt to read or write protected memory. This is usually an indication that the other memory is corrupted.,感谢 microsoft 示例,我这样做了,但我收到了这个错误,我找不到任何关于此的信息。我在任何地方都错了吗?

C++ 头文件

#ifndef KKKKK_V2_EXPORTS
#define KKKKK_V2_API __declspec(dllexport)
#else
#define KKKKK_V2_API __declspec(dllimport)
#endif

extern "C" KKKKK_V2_API can* create_can(string ip, int port);

extern "C" KKKKK_V2_API int connectCan(can* _c);


extern "C" KKKKK_V2_API string browseCan(can* _c,int x);

extern "C" KKKKK_V2_API void dataset_browseCan(can* _c);

extern "C" KKKKK_V2_API void dataset_signals_readingCan(can* _c);

extern "C" KKKKK_V2_API void GI_Can(can* _c);

extern "C" KKKKK_V2_API void ConcludeCan(can* _c);

Cpp 文件

can* create_can(string ip, int port) 
    const char* my_ip=ip.c_str();
    can* _c = new can();
    _c->connection = new connect_tcp((char*)my_ip, port);
    _c->s = _c->connection->ConnectWithTcp();
    _c->list = new LinkedList * [1000];
    return _c;

int connectCan(can* _c) 
    cotp_connection(_c->cotp, _c->connection, _c->response, _c->list, _c->s);
    return 1;

string browseCan(can* _c,int x) 
    int i = 0;
    initiate_request(_c->cotp, _c->mms_obj, _c->connection, _c->response, _c->list, _c->size_encoder, _c->s);
    confirmed_request(_c->cotp, _c->mms_obj, _c->connection, _c->response, _c->list, _c->size_encoder, _c->s);
    continue_confirmed_request_with_more_follows(_c->cotp, _c->mms_obj, _c->connection, _c->response, _c->list, _c->size_encoder, _c->s);
    all_object_browse(_c->cotp, _c->mms_obj, _c->connection, _c->response, _c->list, _c->size_encoder, _c->s);
    auto it = _c->response.object_list.begin();
    while (i < x) 
        it++;
        i++;
    
    return *it; 

void dataset_browseCan(can* _c) 
    dataset_browse(_c->cotp, _c->mms_obj, _c->connection, _c->response, _c->list, _c->size_encoder, _c->s);
    dataset_signals_browse(_c->cotp, _c->mms_obj, _c->connection, _c->response, _c->list, _c->size_encoder, _c->s); 
    _c->signals = new Signals[_c->response.real_signals_and_values.size()];

void dataset_signals_readingCan(can* _c) 
    dataset_signals_reading(_c->cotp, _c->mms_obj, _c->connection, _c->response, _c->list, _c->size_encoder, _c->s, _c->signals);

void GI_Can(can* _c) 
    write_data_pins(_c->cotp, _c->mms_obj, _c->connection, _c->response, _c->list, _c->size_encoder, _c->s, _c->signals);
    general_information(_c->cotp, _c->mms_obj, _c->connection, _c->response, _c->list, _c->size_encoder, _c->s, _c->signals);

void ConcludeCan(can* _c) 
    conclude(_c->cotp, _c->mms_obj, _c->connection, _c->response, _c->list, _c->size_encoder, _c->s, _c->signals);
    release(_c->cotp, _c->mms_obj, _c->connection, _c->response, _c->list, _c->size_encoder, _c->s, _c->signals);

C# 文件

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;


namespace cppDllTest

    class Program
    

        [DllImport(@"C:\Users\serhan.erkovan\source\repos\kkkkk_v2\Debug\kkkkk_v2.dll", CallingConvention = CallingConvention.Cdecl)]
        static extern IntPtr create_can(string my_ip_address, int my_port);
        IntPtr _c;
        _c = create_can("10.6.35.225", 102);   //ERROR IS HERE
    


我放了我的 cpp 文件,但这不是必需的,我知道。也许我在 cpp 文件上错了,因为我放了那个。

在 Dependency Walker,我所有导出的函数在“E”部分显示为灰色。意思是“驻留在所选模块中的 C 导出函数。”

【问题讨论】:

您在“构建平台”中选择了哪个平台?也许这个最佳答案会有所帮助:***.com/a/18252141/3852949 @Storm Visual Studio 2019 (v142) 我为 x64 和 x86 构建,但每次都出现此错误 在与 P/Invoke 交互之前,您是否尝试过编译您的 c++ 代码并检查编译后的二进制文件是否按预期工作?作为旁注,我想指出 _c-&gt;connection = new connect_tcp((char*)my_ip, port); 将导致悬空指针,因为当您离开范围时,ip.c_str() 返回的指针将不再有效,因为它基于临时变量。 它在 c++ 上运行,我试过没有错误。 尝试将can* create_can(string ip, int port)原型更改为can* create_can(const char * ip, int port)并相应地更改c++代码。 C# 中的 string 类型不等同于 C++ 中的 std::string 【参考方案1】:

这里的问题是,正如这里所解释的https://***.com/a/20752021/3852949:

您不能跨互操作边界传递 C++ std::string。您不能在 C# 代码中创建其中之一

您可以更改 C++ 函数签名,使其接受 const char *(即 can* create_can(const char * ip, int port)),或者创建一个调用原始函数的适配器函数:

can* create_can_adapter(const char * ip, int port)

    std::string s(ip);

    return (create_can(s, port));

【讨论】:

以上是关于在 c# System.AccessViolationException 处导出 c++ 函数和使用函数的主要内容,如果未能解决你的问题,请参考以下文章

c# 在 c# 应用程序中保存配置数据的最佳方法是啥。 [复制]

c#快速入门~在java基础上,知道C#和JAVA 的不同即可

如何在 C# 的泛型中使用扩展

在 C# 中定义 F# '**' 运算符

在 C++ 中使用 C# 接口或在 C# 中使用 C++ 接口

在C#中调用exe程序