我在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:'尝试读取或写入受保护的 记忆。这通常表明其他内存已损坏。'
试图找到让这两者相互理解的方法
答案 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++
您的代码存在问题
导出的函数返回指向未定义行为的局部变量的指针。
补充观察
如果您的原始列表是一个数组,为什么还要将它列为一个列表呢?阵列将更容易编组和使用。并且可能也表现得更好。
在定义结构时,您必须明确如何编组字符串以及应该使用的对齐方式。你应该确认一切都符合预期。