我们得到了一个 C# DLL,其中包含加载和操作专有数据格式所需的代码。我们的代码库主要是原生 C++。所以我们可以访问提供的库,我编写了一个 DLL,其中包含
- 实现必要 API 的本机 C++ 包装类
- 一个 C++/CLI 桥接类,用于编组输入和输出数据并将调用委托给 C# DLL。
我编写了一个基本的(本机)C++ 控制台应用程序来测试 API 是否符合我的要求。它做了。然后我编写了一个调用 API 的(本机的,Microsoft Visual Studio)单元测试项目。令人惊讶的是,它在构造接口对象时会因一些未说明的异常而崩溃。
一些最小的代码:
互操作API.h:
#pragma once
#pragma unmanaged
#if defined(INTEROP_API_EXPORTS)
#define INTEROP_API __declspec(dllexport)
#else
#define INTEROP_API __declspec(dllimport)
#endif
#include <string>
class InteropBridgeArchive;
struct InteropRecord
{
std::string Name;
int Id;
std::string Data;
};
class INTEROP_API InteropAPI
{
public:
InteropAPI();
~InteropAPI();
InteropRecord GetRecord(int id) const;
private:
InteropBridgeArchive * impl_;
};
互操作API.cpp:
#pragma managed
#include "InteropBridge.h"
#pragma unmanaged
#include "InteropAPI.h"
InteropAPI::InteropAPI()
: impl_(new InteropBridge())
{
}
InteropAPI::~InteropAPI()
{
delete impl_;
}
InteropRecord InteropAPI::GetRecord(const int id) const
{
return impl_->GetRecord(id);
}
互操作桥.h
#pragma once
#pragma unmanaged
#include "InteropAPI.h"
#pragma managed
#include <vcclr.h>
class InteropBridge
{
public:
InteropArchive();
InteropRecord GetRecord(System::Int32 id) const;
private:
gcroot<InteropCSharpDll::Archive^> archive_;
};
互操作桥.cpp:
#pragma unmanaged
#include <string>
#pragma managed
#include "InteropBridge.h"
#include <msclr/marshal_cppstd.h>
InteropBridge::InteropBridge()
{
archive_ = gcnew InteropCSharpDll::Archive;
}
InteropRecord InteropBridge::GetRecord(const System::Int32 id) const
{
auto return_value = archive_->GetRecord(id);
InteropRecord record;
record.Name = msclr::interop::marshal_as<std::string>(return_value.Name);
record.Id = return_value.Id;
record.Data = msclr::interop::marshal_as<std::string>(return_value.Data);
return record;
}
测试 C# DLL 有这个:
using System.Linq;
namespace InteropCSharpDll
{
public struct Record
{
public string Name;
public int Id;
public string Data;
}
public class Archive
{
public Record GetRecord(int id)
{
return _records.First(r => r.Id == id);
}
private readonly Record[] _records =
{
new Record {Name = "Foo", Id = 0, Data = "Foo.Data"},
new Record {Name = "Bar", Id = 2, Data = "Bar.Data"},
new Record {Name = "Egg", Id = 7, Data = "Egg.Data"},
};
}
}
显然,如果这种混合结构不能作为本机代码进行单元测试,我们就无法测试任何接触它的东西,因此了解它崩溃的原因非常重要。此代码作为本机 C++ 项目运行良好:
#include <cstdio>
#include <iostream>
#include "../InteropCppCliBridgeDll/InteropAPI.h"
#pragma comment(lib, "../x64/Debug/InteropCppCliBridgeDll.lib")
int main(int , char ** )
{
const InteropAPI archive;
const auto record = archive.GetRecord(0);
std::cout << "Name: " << record.Name << "\n";
std::cout << "Id: " << record.Id<< "\n";
std::cout << "Data: " << record.Data<< "\n\n";
}
而在本机单元测试项目中,崩溃发生在行内或行周围
archive_ = gcnew InteropCSharpDll::Archive;