Writing a managed wrapper for unmanaged (C ++) code - custom types / structures

faacEncConfigurationPtr FAACAPI faacEncGetCurrentConfiguration( faacEncHandle hEncoder); 

I am trying to create a simple wrapper for this C ++ library; I have never done more than a very simple p / invoke interop before - as a single function call with primitive arguments.

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

FAACAPI is defined as: #define FAACAPI __stdcall

defined by 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; 

AFAIK does this mean that the return type of the function is a reference to this structure?

And 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; 

So, inside this structure we see many other types ... hmm.

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

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

If so, can the runtime automatically "map" these objects to each other? And, should I create these "mapped" types for all types in these types of return types / hierarchy of parameter types, until I get all the primitives?

I know that this is a wide topic, any advice on how to quickly get up to speed, what I need to learn how to do it, are very much appreciated! Thanks!

+4
source share
2 answers

You are on the right track with how you need to create managed structures that are immutable structures for use with P / Invoke.

However, this is not the best strategy for interacting with unmanaged libraries, because using this API from C # will still resemble using the C API - creating and initializing a structure, passing it to a function, and getting another structure in return.

It is good to use P / Invoke to call an odd function, which otherwise does not appear as a .NET API, but for a full-blown API shell, I highly recommend using managed C ++ (C ++ / CLI). This is absolutely unprecedented for creating unmanaged interaction layers for .NET.

The biggest problem would be to convert this essentially C interface to an object-oriented interface, where you call methods from objects, rather than calling global functions with public member structures.

When you start writing complex structure graphs for P / Invoke, you will have to deal with quite a bit of โ€œmagicโ€ that defines how managed primitive types are converted to unmanaged types. Often using the wrong types will result in a runtime error.

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

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

+4
source

Yes, you need to declare all of these structures in C #. Be careful to declare members with the 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.

0
source

Source: https://habr.com/ru/post/1311372/


All Articles