You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将C++ DLL返回的std::vector<std::string>数据显示在C#窗体的ListBox中

解决方案:在C#窗体中调用C++ DLL的std::vector返回值并填充ListBox

因为C++的std::vector<std::string>和C#的托管类型无法直接通过P/Invoke交互,我们需要通过兼容接口包装或者中间层来实现,下面是两种实用的方案:


方案一:修改C++ DLL,导出C风格兼容接口

这是最直接的方式,无需额外中间项目,只需调整DLL导出函数,用C语言兼容的类型传递数据:

步骤1:修改C++ DLL代码

把原函数包装成C风格导出函数,避免名字修饰,同时用char**和长度来传递字符串集合:

#include <vector>
#include <string>
#include <cstring>

// 原函数保持不变
std::vector<std::string> foo(std::vector<std::string> strVec) {
    return strVec;
}

// 导出C风格的包装函数
extern "C" __declspec(dllexport) char** FooWrapper(const char** inputArray, int inputCount, int* outCount) {
    // 将C风格数组转为std::vector<std::string>
    std::vector<std::string> inputVec;
    for (int i = 0; i < inputCount; ++i) {
        inputVec.push_back(inputArray[i]);
    }

    // 调用原函数
    std::vector<std::string> resultVec = foo(inputVec);
    *outCount = resultVec.size();

    // 分配返回的char**数组
    char** resultArray = new char*[resultVec.size()];
    for (int i = 0; i < resultVec.size(); ++i) {
        const char* str = resultVec[i].c_str();
        resultArray[i] = new char[strlen(str) + 1];
        strcpy_s(resultArray[i], strlen(str) + 1, str);
    }

    return resultArray;
}

// 导出释放内存的函数,避免内存泄漏
extern "C" __declspec(dllexport) void FreeStringArray(char** array, int count) {
    for (int i = 0; i < count; ++i) {
        delete[] array[i];
    }
    delete[] array;
}

步骤2:在C#窗体项目中调用

在窗体类里添加P/Invoke声明,然后调用函数并填充ListBox:

using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace YourWinFormApp
{
    public partial class YourForm : Form
    {
        // P/Invoke声明C++ DLL的导出函数
        [DllImport("YourCppDll.dll", CallingConvention = CallingConvention.Cdecl)]
        private static extern IntPtr FooWrapper(IntPtr inputArray, int inputCount, out int outCount);

        [DllImport("YourCppDll.dll", CallingConvention = CallingConvention.Cdecl)]
        private static extern void FreeStringArray(IntPtr array, int count);

        public YourForm()
        {
            InitializeComponent();
        }

        // 示例调用方法,比如按钮点击事件
        private void btnCallFoo_Click(object sender, EventArgs e)
        {
            // 准备输入参数(示例输入)
            string[] inputStrings = { "Hello", "World", "C++", "C#" };
            
            // 将C#字符串数组转为C风格的char**
            IntPtr[] inputPtrs = new IntPtr[inputStrings.Length];
            for (int i = 0; i < inputStrings.Length; ++i)
            {
                inputPtrs[i] = Marshal.StringToHGlobalAnsi(inputStrings[i]);
            }
            IntPtr inputArray = Marshal.AllocHGlobal(IntPtr.Size * inputPtrs.Length);
            Marshal.Copy(inputPtrs, 0, inputArray, inputPtrs.Length);

            try
            {
                // 调用DLL函数
                int outCount;
                IntPtr resultArray = FooWrapper(inputArray, inputStrings.Length, out outCount);

                // 将返回的char**转为C#字符串数组
                string[] resultStrings = new string[outCount];
                IntPtr[] resultPtrs = new IntPtr[outCount];
                Marshal.Copy(resultArray, resultPtrs, 0, outCount);
                for (int i = 0; i < outCount; ++i)
                {
                    resultStrings[i] = Marshal.PtrToStringAnsi(resultPtrs[i]);
                }

                // 填充ListBox
                lstData.Items.Clear();
                lstData.Items.AddRange(resultStrings);

                // 释放返回的内存
                FreeStringArray(resultArray, outCount);
            }
            finally
            {
                // 释放输入参数的内存
                Marshal.FreeHGlobal(inputArray);
                foreach (IntPtr ptr in inputPtrs)
                {
                    Marshal.FreeHGlobal(ptr);
                }
            }
        }
    }
}

方案二:使用C++/CLI作为中间包装层

如果不想修改原C++ DLL代码,或者需要更优雅的类型转换,可以用C++/CLI创建包装类库,直接桥接原生C++和.NET类型:

步骤1:创建C++/CLI类库项目

在Visual Studio中创建CLR类库项目,添加对原C++ DLL的引用(或直接包含原函数头文件和链接库)。

步骤2:编写包装类

#include <vector>
#include <string>
#include "YourOriginalCppHeader.h" // 包含原foo函数的头文件

using namespace System;
using namespace System::Collections::Generic;

namespace CppCliWrapper
{
    public ref class FooWrapper
    {
    public:
        static List<String^>^ CallFoo(List<String^>^ inputList)
        {
            // 将.NET List<String>转为std::vector<std::string>
            std::vector<std::string> inputVec;
            for each (String^ str in inputList)
            {
                pin_ptr<const wchar_t> wstr = PtrToStringChars(str);
                std::string nativeStr(wstr);
                inputVec.push_back(nativeStr);
            }

            // 调用原C++函数
            std::vector<std::string> resultVec = foo(inputVec);

            // 将std::vector<std::string>转为.NET List<String>
            List<String^>^ resultList = gcnew List<String^>();
            for (const auto& str : resultVec)
            {
                resultList->Add(gcnew String(str.c_str()));
            }

            return resultList;
        }
    };
}

步骤3:在C#窗体项目中使用

引用C++/CLI类库,直接调用并填充ListBox:

using System;
using System.Collections.Generic;
using System.Windows.Forms;
using CppCliWrapper; // 引用包装类库

namespace YourWinFormApp
{
    public partial class YourForm : Form
    {
        public YourForm()
        {
            InitializeComponent();
        }

        private void btnCallFoo_Click(object sender, EventArgs e)
        {
            // 准备输入
            List<string> inputList = new List<string> { "Test1", "Test2", "Test3" };
            
            // 调用包装函数
            List<string> resultList = FooWrapper.CallFoo(inputList);

            // 填充ListBox
            lstData.Items.Clear();
            lstData.Items.AddRange(resultList.ToArray());
        }
    }
}

注意事项

  • 确保C++ DLL和C#项目的平台一致(比如都是x86或x64),否则会出现调用失败。
  • 方案一中必须调用FreeStringArray释放内存,避免内存泄漏。
  • 如果需要处理Unicode字符串,可把char*换成wchar_t*,对应C#中用Marshal.StringToHGlobalUni和Marshal.PtrToStringUni。

内容的提问来源于stack exchange,提问作者east1000

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.29 14:22:35