Wrapping native C++ struct in C++/CLI
Asked Answered
R

3

9

I've never worked with either C++ or C++/CLI, but I would like to use a native C++ library in a C# project. I googled a bit, learnt a few things about C++/CLI and decided to give it a head start. But I'm not sure if I'm doing any of it right.

I have the following struct in a native namespace:

avcodec.h

typedef struct AVCodecDescriptor {
    enum AVCodecID     id;
    enum AVMediaType type;

    const char      *name;
    const char *long_name;
    int             props;
} AVCodecDescriptor;

Now I want to wrap this struct in C++/CLI for using it in C#:

public ref struct AVCodecDescriptorWrapper {

    private:
        struct AVCodecDescriptor *_avCodecDescriptor;

    public:
        AVCodecDescriptorWrapper() {
            _avCodecDescriptor = new AVCodecDescriptor();
        }
        ~AVCodecDescriptorWrapper() {
            delete _avCodecDescriptor;
        }

        // what do?
        property AVCodecID Id {
            AVCodecID get() {
                return; // what comes here ????
            }
        }

};

However, it seems like I'm doing something horribly wrong since I'm not even able to see the fields of the struct AVCodecDescriptor in C++/CLI. Do I have to wrap the enums in the struct to? Do I have to copy them into C++/CLI and cast it (well, enum AVCodecID has like 350 values - a copy/paste seems ridiculus.)

Rayerayfield answered 30/1, 2014 at 15:28 Comment(4)
Using new and delete is rather pointless here. private: AVCodecDescriptor _avCodecDescriptor; suffices. And yes, you have to wrap everything. Including the enums. You need them to be declared as managed types. And then map them from the unmanaged to managed. As for the way you are wrapping, should you really do it that way? How are you going to manage the lifetime of the const char* members. Frankly, it's not obvious to me that C++/CLI is going to be easier than p/invoke.Kunlun
@DavidHeffernan 1) private: AVCodecDescriptor _avCodecDescriptor doesn't work since VS tells me I can not use an unmanaged member in a managed class. 2) Thank you for clarifying! 3) How else I have to wrap? It's the way a lot of tutorials are handling it. 4) I'm not familiar with P/Invoke either. But I need to start somewhere. I heard a lot of people saying P/Invoke can be significantly slower and since the library I'm working with is ffmpeg.. well, you know.Rayerayfield
return (ManagedAVCodecID)_avCodecDescriptor->id; You need a finalizer as well. Pretty sure ffmpeg has already been wrapped before. Lots of dead projects though, getting it actually finished appears to be a high obstacle.Winstead
@HansPassant Not only lots of dead projects, but also trillions of so called 'wrappers' that doesn't really wrap the ffmpeg libraries, but just construct command line arguments and pass them to ffmpeg. :/Rayerayfield
R
5

You need to create a equivalent CLI class of native struct and Enums.

public ref class ManagedAVCodecDescriptor {
    ManagedAVCodecIDClass id;
    ManagedAVMediaTypeClass type;

    String^ name;
    String^ long_name;
    int props;
};

Enum equivalent class will look like this:

public enum class ManagedAVCodecIDClass
{
    xyx = 1,
    abc = 2,
    ...
}

Now in your AVCodecDescriptorWrapper you should get AVCodecDescriptor object and put all information in the ManagedAVCodecDescriptor object and pass it to C# class.

ManagedAVCodecDescriptor^ mObject = gcnew ManagedAVCodecDescriptor();
mObject.setSomeValue(nativeStruct->somevalue);

and pass mObject to C# code as general C# object.

Reitman answered 6/2, 2014 at 17:29 Comment(0)
F
1

I prefer to use .NET structure within native code. You define:

public enum class AVCodecID : long
{
    mp4 = 1,
    mpeg2 = 2,
    ...

}

public ref class AVCodecDescriptor
{
    AVCodecID id,
    ...
    System::String name
    ...
}

and whenever you need in C++ code you will call

AVCodecDescriptor cd = gcnew AVCodecDescriptor();

It is not always handy, you need files using it compiled with /clr switch and sometimes you can get mad with converting managed/unmanaged strings, but many times this was quite suitable for me. Anyway you can use .NET enums quite easily in C++ native code, typing enum values to int.

Finalize answered 30/1, 2014 at 16:1 Comment(1)
The native structures already exist; they are part of an existing native library.Proximo
P
1

Does this not work?

   property int Id {
        int get() {
            return _avCodecDescriptor->id;
        }
    }

BTW you should be using some smart pointer for lifetime management of the native object, as right now you will leak memory if the .NET object is finalizer instead of disposed. For an example, see my scoped_ptr for C++/CLI (ensure managed object properly frees owned native object)

Proximo answered 6/2, 2014 at 17:57 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.