views:

75

answers:

2
faacEncConfigurationPtr FAACAPI faacEncGetCurrentConfiguration(
       faacEncHandle hEncoder);

I'm trying to come up with a simple wrapper for this C++ library; I've never done more than very simple p/invoke interop before - like one function call with primitive arguments.

So, given the above C++ function, for example, what should I do to deal with the return type, and parameter?

FAACAPI is defined as: #define FAACAPI __stdcall

faacEncConfigurationPtr is defined:

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;

AFAIK this means that the return type of the function is a reference to this struct?

And faacEncHandle is:

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;

So within that struct we see a lot of other types... hmm.

Essentially, I'm trying to figure out how to deal with these types in my managed wrapper?
Do I need to create versions of these types/structs, in C#? Something like this:

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

If so then can the runtime automatically "map" these objects onto eachother? And, would I have to create these "mapped" types for all the types in these return types/parameter type hierarchies, all the way down until I get to all primitives?

I know this is a broad topic, any advice on getting up-to-speed quickly on what I need to learn to make this happen would be very much appreciated! Thanks!

+3  A: 

Your are on the right track with how you would need to create managed structures that represent unamanged structures for use with P/Invoke.

It is however not the best strategy for interop with unmanaged libraries, because using this API from C# would still feel like using a C API - create and initialise a structure, pass it to a function and get some other structure in return.

It is OK to use P/Invoke for an odd function call that is not otherwise exposed as .NET API, but for a full blown API wrapper I would highly recommend using managed C++(C++/CLI). It is absolutely unparalleled in creating unmanaged interop layers for .NET.

The biggest challenge would be to convert this essentially C interface into an object orientated interface where you call methods off objects, as opposed to calling global functions with structures of all-public members.

As you start writing elaborate structure graphs for P/Invoke you would yourself having to deal with quite a bit of "magic" that governs how managed primitive types convert to unmanaged types. Often, using incorrect types will cause a run-time error.

With managed C++ (IJW - It Just Works) you define managed structures, classes, interfaces in C++, which allows more natural use of the underlying library and a more native interface to your C# application.

This is a great overview of C++/CLI. Also MSDN has extensive documentation for all managed C++ features.

Igor Zevaka
great reply, thanks for the info, hadn't thought of managed C++, will try to look into it..So far I've continued with the C# attempt, though it's a bit unwieldy.. say to wrap this:int FAACAPI faacEncEncode(faacEncHandle hEncoder, int32_t *inputBuffer, unsigned int samplesInput, unsigned char *outputBuffer, unsigned int bufferSize);why the unsigned char*? does that map to string?does the 'int' indeed map to System.Int16 (as the other reply indicated?), etc. and would these questions be more obvious in a managed C++ solution? hmm [feeling glad to work normally in pure .NET :)]
Bobby
A: 

Yes, you would need to declare all these structures in c#. Be careful to declare members with correct sizes. For example, 'long' is 32-bit in C++, but 64-bit in C#. For a pointer or void* in C++, use IntPtr in C#, etc.

logicnp