为非托管(C++)代码编写托管包装器 - 自定义类型/结构体

4
faacEncConfigurationPtr FAACAPI faacEncGetCurrentConfiguration(
       faacEncHandle hEncoder);

我正在尝试为这个C++库设计一个简单的包装器;我之前只做过非常简单的P/Invoke互操作,比如一些带有基本参数的函数调用。

所以,举例来说,对于上面的C++函数,我应该怎么处理返回类型和参数呢?

FAACAPI被定义为:#define FAACAPI __stdcall

faacEncConfigurationPtr被定义为:

typedef struct faacEncConfiguration
{
    int version;
    char *name;
    char *copyright;
    unsigned int mpegVersion;
    unsigned long bitRate;
    unsigned int inputFormat;
    int shortctl;

    psymodellist_t *psymodellist;

    int channel_map[64]; 

} faacEncConfiguration, *faacEncConfigurationPtr;

据我所知,这意味着函数的返回类型是对此结构体的引用?
而faacEncHandle是:
typedef struct {
    unsigned int numChannels;
    unsigned long sampleRate;
...
    SR_INFO *srInfo;
    double *sampleBuff[MAX_CHANNELS];
...
    double *freqBuff[MAX_CHANNELS];
    double *overlapBuff[MAX_CHANNELS];

    double *msSpectrum[MAX_CHANNELS];

    CoderInfo coderInfo[MAX_CHANNELS];
    ChannelInfo channelInfo[MAX_CHANNELS];
    PsyInfo psyInfo[MAX_CHANNELS];
    GlobalPsyInfo gpsyInfo;
    faacEncConfiguration config;

    psymodel_t *psymodel;

    /* quantizer specific config */
    AACQuantCfg aacquantCfg;

 /* FFT Tables */
    FFT_Tables fft_tables;

    int bitDiff;
} faacEncStruct, *faacEncHandle;

因此,在该结构体中,我们看到了许多其他类型...嗯。

基本上,我正在尝试弄清楚如何在我的托管包装器中处理这些类型?
我需要在C#中创建这些类型/结构体的版本吗?类似于这样:

[StructLayout(LayoutKind.Sequential)]
struct faacEncConfiguration
{
    uint useTns;
    ulong bitRate;
...
}

如果是这样,运行时是否可以自动将这些对象“映射”到彼此? 而且,我是否需要为这些返回类型/参数类型层次结构中的所有类型创建这些“映射”类型,一直到我获得所有基元类型为止?
我知道这是一个广泛的话题,如果您能给我一些建议,让我快速了解我需要学习什么才能实现这一点,那将非常感激!谢谢!
2个回答

4

你的想法是正确的,你需要创建托管结构来代表未托管的结构以便与P/Invoke一起使用。

然而,这不是与未托管库进行交互的最佳策略,因为从C#使用此API仍会感觉像使用C API-创建和初始化结构,将其传递给函数并获得其他结构作为返回值。

对于一个完整的API包装器,使用P/Invoke调用一个奇怪的未公开.NET API的函数是可以的,但我强烈建议使用托管C++(C++/CLI)。它在为.NET创建未托管互操作层方面绝对无与伦比。

最大的挑战是将这个本质上的C接口转换为面向对象的接口,在该接口中,您通过对象调用方法,而不是使用所有公共成员的结构调用全局函数。

当您开始编写复杂的结构图形以供P/Invoke使用时,您将不得不处理相当多的“魔术”,这些“魔术”控制着托管原始类型如何转换为未托管类型。通常,使用不正确的类型会导致运行时错误。

使用托管C++(IJW-It Just Works),您可以在C++中定义托管结构、类、接口,这允许更自然地使用底层库,并为您的C#应用程序提供更本地的接口。

这篇文章是 C++/CLI 的一个很好的概述。此外,MSDN对所有托管的C++功能都有广泛的文档。


很棒的回复,感谢提供信息。我还没想到使用Managed C++,会尝试研究一下。 目前我继续使用C#尝试,但有些棘手..比如要包装这个: int FAACAPI faacEncEncode(faacEncHandle hEncoder, int32_t *inputBuffer, unsigned int samplesInput, unsigned char outputBuffer, unsigned int bufferSize); 为什么是unsigned char?它是否映射到字符串? “int”是否确实映射到System.Int16(如其他回复所示)?如果使用Managed C++解决方案,这些问题是否更为明显?哈哈(为在纯.NET中正常工作而感到高兴) - Bobby

0

是的,您需要在C#中声明所有这些结构。请注意使用正确大小来声明成员。例如,在C++中,“long”是32位的,但在C#中是64位的。对于C++中的指针或void*,请在C#中使用IntPtr。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接