首页
学习
活动
专区
圈层
工具
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

基于C++动态库DLL应用开发

在跨语言调用中,如何确保传入的参数正确,尤其是字符串和结构体指针,避免崩溃或内存错误。

现在需要分步骤处理:

设计学生和课程的结构体,确保学生包含课程表。可能每个学生有一个课程数组,或者指向课程表的指针。

实现C++类来管理学生和课程,比如StudentManager类,内部使用容器存储学生,每个学生包含课程列表。

将C++类封装为C风格的API,使用句柄(void*)来隐藏对象实例,防止直接暴露C++对象。

定义导出函数,包括创建/销毁句柄、增删改查学生、遍历学生和课程的回调。

实现回调函数类型,比如学生回调和课程回调,允许用户传递自定义函数处理数据。

编译生成DLL,确保导出符号正确,可供其他语言调用。

在WPF中使用C#通过DllImport调用DLL函数,处理结构体和回调。需要注意结构体的内存布局和编码。

在Java中使用JNA定义接口,映射结构体和回调函数,处理嵌套的数据结构。

以下是分步骤的完整实现方案,涵盖 C++ 动态库封装、WPF (C#) 和 Java 的调用示例:

步骤 1:C++ 动态库实现(嵌套结构 + 回调)

1.1 头文件 StudentCourseDll.h

#ifndef STUDENT_COURSE_DLL_H

#define STUDENT_COURSE_DLL_H

#ifdef __cplusplus

extern "C" {

#endif

// 定义课程结构体

typedef struct {

int courseId;

char courseName;

} Course;

// 定义学生结构体(嵌套课程表)

typedef struct {

int studentId;

char studentName;

Course* courses; // 课程数组指针

int courseCount; // 课程数量

} Student;

// 定义句柄类型(隐藏 C++ 对象)

typedef void* StudentManagerHandle;

// ------------------ 回调函数类型定义 ------------------

// 学生信息回调

typedef void (*StudentCallback)(const Student* student, void* userData);

// 课程信息回调

typedef void (*CourseCallback)(const Course* course, void* userData);

// ------------------ 导出函数声明 ------------------

// 创建和销毁管理器

__declspec(dllexport) StudentManagerHandle create_manager();

__declspec(dllexport) void destroy_manager(StudentManagerHandle handle);

// 学生操作

__declspec(dllexport) void add_student(StudentManagerHandle handle, const Student* student);

__declspec(dllexport) bool delete_student(StudentManagerHandle handle, int studentId);

__declspec(dllexport) Student* find_student(StudentManagerHandle handle, int studentId);

__declspec(dllexport) void update_student(StudentManagerHandle handle, int studentId, const Student* newData);

// 遍历学生和课程(使用回调)

__declspec(dllexport) void foreach_student(StudentManagerHandle handle, StudentCallback studentCallback, void* userData);

__declspec(dllexport) void foreach_course(StudentManagerHandle handle, int studentId, CourseCallback courseCallback, void* userData);

#ifdef __cplusplus

}

#endif

#endif // STUDENT_COURSE_DLL_H

1.2 实现文件 StudentCourseDll.cpp

#include "StudentCourseDll.h"

#include <vector>

#include <algorithm>

// C++ 学生管理类

class StudentManager {

private:

std::vector<Student*> students;

public:

void addStudent(const Student* s) {

Student* newStudent = new Student(*s);

newStudent->courses = new Course[s->courseCount];

std::copy(s->courses, s->courses + s->courseCount, newStudent->courses);

students.push_back(newStudent);

}

bool deleteStudent(int id) {

auto it = std::find_if(students.begin(), students.end(),

[id](const Student* s) { return s->studentId == id; });

if (it != students.end()) {

delete[] (*it)->courses;

delete *it;

students.erase(it);

return true;

}

return false;

}

Student* findStudent(int id) {

auto it = std::find_if(students.begin(), students.end(),

[id](const Student* s) { return s->studentId == id; });

return (it != students.end()) ? *it : nullptr;

}

void updateStudent(int id, const Student* newData) {

Student* s = findStudent(id);

if (s) {

s->studentId = newData->studentId;

strncpy(s->studentName, newData->studentName, 50);

// 更新课程(此处简化逻辑)

delete[] s->courses;

s->courses = new Course[newData->courseCount];

s->courseCount = newData->courseCount;

std::copy(newData->courses, newData->courses + newData->courseCount, s->courses);

}

}

void foreachStudent(StudentCallback callback, void* userData) {

for (const auto& s : students) {

callback(s, userData);

}

}

void foreachCourse(int studentId, CourseCallback callback, void* userData) {

Student* s = findStudent(studentId);

if (s) {

for (int i = 0; i < s->courseCount; i++) {

callback(&s->courses[i], userData);

}

}

}

~StudentManager() {

for (auto s : students) {

delete[] s->courses;

delete s;

}

}

};

// ------------------ C 风格导出函数实现 ------------------

extern "C" {

StudentManagerHandle create_manager() {

return new StudentManager();

}

void destroy_manager(StudentManagerHandle handle) {

delete static_cast<StudentManager*>(handle);

}

void add_student(StudentManagerHandle handle, const Student* student) {

static_cast<StudentManager*>(handle)->addStudent(student);

}

bool delete_student(StudentManagerHandle handle, int studentId) {

return static_cast<StudentManager*>(handle)->deleteStudent(studentId);

}

Student* find_student(StudentManagerHandle handle, int studentId) {

return static_cast<StudentManager*>(handle)->findStudent(studentId);

}

void update_student(StudentManagerHandle handle, int studentId, const Student* newData) {

static_cast<StudentManager*>(handle)->updateStudent(studentId, newData);

}

void foreach_student(StudentManagerHandle handle, StudentCallback callback, void* userData) {

static_cast<StudentManager*>(handle)->foreachStudent(callback, userData);

}

void foreach_course(StudentManagerHandle handle, int studentId, CourseCallback callback, void* userData) {

static_cast<StudentManager*>(handle)->foreachCourse(studentId, callback, userData);

}

}

1.3 编译 DLL

使用 MinGW 编译命令:

g++ -shared -o StudentCourseDll.dll StudentCourseDll.cpp -I. -Wl,--out-implib,libStudentCourseDll.a -static-libgcc -static-libstdc++

步骤 2:WPF (C#) 调用示例

2.1 C# 结构体定义和 P/Invoke

using System;

using System.Runtime.InteropServices;

using System.Windows;

public partial class MainWindow : Window {

// 定义结构体

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]

public struct Course {

public int courseId;

[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 50)]

public string courseName;

}

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]

public struct Student {

public int studentId;

[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 50)]

public string studentName;

public IntPtr courses; // Course 数组指针

public int courseCount;

}

// 定义回调委托

[UnmanagedFunctionPointer(CallingConvention.Cdecl)]

public delegate void StudentCallback(IntPtr student, IntPtr userData);

[UnmanagedFunctionPointer(CallingConvention.Cdecl)]

public delegate void CourseCallback(IntPtr course, IntPtr userData);

// DLL 函数声明

[DllImport("StudentCourseDll.dll", CallingConvention = CallingConvention.Cdecl)]

public static extern IntPtr create_manager();

[DllImport("StudentCourseDll.dll", CallingConvention = CallingConvention.Cdecl)]

public static extern void destroy_manager(IntPtr handle);

[DllImport("StudentCourseDll.dll", CallingConvention = CallingConvention.Cdecl)]

public static extern void add_student(IntPtr handle, ref Student student);

[DllImport("StudentCourseDll.dll", CallingConvention = CallingConvention.Cdecl)]

public static extern void foreach_student(IntPtr handle, StudentCallback callback, IntPtr userData);

private IntPtr managerHandle;

public MainWindow() {

InitializeComponent();

managerHandle = create_manager();

// 添加学生和课程

Course[] courses = {

new Course { courseId = 1, courseName = "Math" },

new Course { courseId = 2, courseName = "Physics" }

};

Student student = new Student {

studentId = 101,

studentName = "Alice",

courseCount = courses.Length,

courses = Marshal.AllocHGlobal(Marshal.SizeOf<Course>() * courses.Length)

};

// 复制课程数据

IntPtr current = student.courses;

foreach (var course in courses) {

Marshal.StructureToPtr(course, current, false);

current = IntPtr.Add(current, Marshal.SizeOf<Course>());

}

add_student(managerHandle, ref student);

Marshal.FreeHGlobal(student.courses);

// 遍历学生

StudentCallback studentCallback = (studentPtr, userData) => {

Student s = Marshal.PtrToStructure<Student>(studentPtr);

Console.WriteLine($"Student: {s.studentName}");

};

foreach_student(managerHandle, studentCallback, IntPtr.Zero);

}

protected override void OnClosed(EventArgs e) {

destroy_manager(managerHandle);

base.OnClosed(e);

}

}

步骤 3:Java 调用示例(JNA)

3.1 Java 接口定义

import com.sun.jna.*;

import java.util.*;

public class TestStudentDll {

public interface StudentCourseDll extends Library {

StudentCourseDll INSTANCE = Native.load("StudentCourseDll", StudentCourseDll.class);

// 定义结构体

class Course extends Structure {

public int courseId;

public byte[] courseName = new byte;

@Override

protected List<String> getFieldOrder() {

return Arrays.asList("courseId", "courseName");

}

}

class Student extends Structure {

public int studentId;

public byte[] studentName = new byte;

public Pointer courses;

public int courseCount;

@Override

protected List<String> getFieldOrder() {

return Arrays.asList("studentId", "studentName", "courses", "courseCount");

}

}

// 回调接口

interface StudentCallback extends Callback {

void invoke(Pointer student, Pointer userData);

}

// 导出函数

Pointer create_manager();

void destroy_manager(Pointer handle);

void add_student(Pointer handle, Student.ByReference student);

void foreach_student(Pointer handle, StudentCallback callback, Pointer userData);

}

public static void main(String[] args) {

Pointer manager = StudentCourseDll.INSTANCE.create_manager();

// 添加学生

StudentCourseDll.Student.ByReference student = new StudentCourseDll.Student.ByReference();

student.studentId = 101;

student.studentName = "Alice".getBytes();

student.courseCount = 2;

// 创建课程数组

StudentCourseDll.Course[] courses = new StudentCourseDll.Course;

courses = new StudentCourseDll.Course();

courses.courseId = 1;

courses.courseName = "Math".getBytes();

courses = new StudentCourseDll.Course();

courses.courseId = 2;

courses.courseName = "Physics".getBytes();

// 分配内存并写入课程数据

int courseSize = new StudentCourseDll.Course().size();

student.courses = new Memory(courseSize * 2);

for (int i = 0; i < 2; i++) {

courses[i].write();

byte[] bytes = courses[i].getPointer().getByteArray(0, courseSize);

student.courses.write(i * courseSize, bytes, 0, bytes.length);

}

StudentCourseDll.INSTANCE.add_student(manager, student);

// 遍历学生

StudentCourseDll.StudentCallback callback = (studentPtr, userData) -> {

StudentCourseDll.Student s = new StudentCourseDll.Student();

s.setAutoRead(false);

s.getPointer().share(0).write(studentPtr.getByteArray(0, s.size()), 0, s.size());

s.read();

System.out.println("Student: " + new String(s.studentName).trim());

};

StudentCourseDll.INSTANCE.foreach_student(manager, callback, null);

StudentCourseDll.INSTANCE.destroy_manager(manager);

}

}

关键点说明

嵌套结构处理

在 C++ 中,学生结构体通过指针动态管理课程数组。

C# 使用 Marshal.AllocHGlobal 分配非托管内存,Java 使用 JNA 的 Memory 类。

回调机制

C# 通过 UnmanagedFunctionPointer 定义委托。

Java 通过 JNA 的 Callback 接口实现回调。

内存管理

C++ 动态库负责内部对象的内存分配和释放。

C# 和 Java 需手动释放非托管内存(如 Marshal.FreeHGlobal)。

跨语言兼容性

结构体的内存布局必须严格匹配(LayoutKind.Sequential)。

字符串使用 ByValTStr 或 byte 确保兼容性。

调试建议

在 C++ 中添加日志输出,验证回调触发顺序。

使用工具(如 Dependency Walker)检查 DLL 导出函数。

  • 发表于:
  • 原文链接https://page.om.qq.com/page/OrHAXFKPcZI4Wl6vDNwSX9gQ0
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券