导入C ++函数将结构的指针返回到VB.NET中

时间:2017-12-09 13:29:08

标签: c++ vb.net struct dllimport

我在C ++中创建了一个简单的DLL,其唯一目的是隔离问题并在小范围内测试导入函数的函数,该函数返回具有不同类型成员的结构列表。

dll_header.h

#ifdef MY_DLL_EXPORTS
#define MY_DLL_API __declspec(dllexport)
#else
#define MY_DLL_API __declspec(dllimport)
#endif

enum color_type
{
    RGB = 1,
    MONO = 2
};

struct my_struct
{
    unsigned char *name;
    char *value;
    color_type type;
    my_struct* next;
};

extern "C" struct my_struct MY_DLL_API * get_list(void);

dll_header.cpp

#include "dll_header.h"

MY_DLL_API my_struct * get_list(void)
{
    my_struct my_list[2];

    unsigned char name1[] = "name1";
    unsigned char name2[] = "name2";

    char val1[] = "val1";
    char val2[] = "val2";

    my_list[0].name = name1;
    my_list[0].value = val1;
    my_list[0].type = RGB;
    my_list[0].next = &my_list[1];

    my_list[0].name = name2;
    my_list[0].value  = val2;
    my_list[0].type = MONO;
    my_list[0].next = NULL;

    return my_list;
}

就像我说的那样,我必须使用这些数据类型(不能将它们更改为字符串或其他任何东西,因为我正在测试某些东西而且我需要它们这样)

现在,在我的VB.NET应用程序中,我导入并尝试从DLL中检索这样的列表

Form1.vb的

Imports System.Runtime.InteropServices
Imports System.Text

Public Class Form1
    Public Enum color_type
        RGB = 1
        COLOR = 2
    End Enum

    Private Structure my_struct
        Public name As Byte()
        Public value As Char()
        Public type As color_type
        Public next As IntPtr
    End Structure

    Private Declare Function get_list Lib "my_lib.dll" () As IntPtr

    Private my_list As List(Of my_struct)

    Private Sub get_list()
        Dim my_list_pointer As IntPtr = get_list()

        my_list = New List(Of my_struct)

        Dim my_item As my_struct

        While my_list_pointer <> IntPtr.Zero
            my_item = CType(Marshal.PtrToStructure(my_list_pointer, GetType(my_struct)), my_struct)

            my_list.Add(my_item)

            my_list_pointer = my_item.next
        End While
    End Sub

我已经尝试了很多其他方法,特别是更改数据类型,但到目前为止,我在尝试运行代码时遇到了这个异常:

  

System.AccessViolationException:'尝试读取或写入受保护的   记忆。这通常表明其他内存已损坏。'

试图找到让这两者相互理解的方法

1 个答案:

答案 0 :(得分:0)

使用混合模式C ++在本机和托管类型之间进行转换,或使用与P / Invoke兼容的类型。

了解Win32如何定义结构(以及使用它们的函数)是一个很好的开始,可以帮助您了解如何定义兼容结构,因为P / Invoke的主要目的之一是能够从托管代码中使用Win32 API。

如果你选择混合模式,那么你可以在两个世界之间进行任何必要的翻译,因为你可以在同一个程序集中混合原生C ++和C ++ / CLI。基本上,您可以编写将本机结构转换为托管结构的代码,然后VB.NET将能够使用该托管代码(假设您使用VB.NET中可用的类型)。

好吧,如果你选择混合模式路由,你通常会得到3个DLL / Assemblies / Executable,就像拥有原始C ++ DLL(本机代码),VB.NET代码(托管)和混合模式一样C ++汇编介于两者之间。

<强>更新

虽然如果列表是只读的,提供代码可能相对容易,但如果不是这种情况,则根据预期使用代码的方式以及现有DLL中的可用函数是多少可能会困难得多

起点是在C ++ / CLI中创建ref class

一些类似的问题

https://bytes.com/topic/c-sharp/answers/674468-passing-linked-list-c-dll-c-pinvoke

Return list of points (x,y,z) from C to C# using PInvoke

PInvoke of self referential struct from C++

您的代码存在问题

导出的函数返回指向未定义行为的局部变量的指针。

补充观察

如果您的原始列表是一个数组,为什么还要将它列为一个列表呢?阵列将更容易编组和使用。并且可能也表现得更好。

在定义结构时,您必须明确如何编组字符串以及应该使用的对齐方式。你应该确认一切都符合预期。