Search code examples
c#c++dlltizennui

How to integrate C++ .dll file to C# Tizen NUI application?


Currently developing a normal C# Tizen NUI application using Visual Studio. It's helpful because of its ready made templates. Haven't modified it a bit. It looks like this:

//Main.cs
using System;
using Tizen.NUI;
using Tizen.NUI.BaseComponents;

namespace TizenDotNetApp
{
    class Program : NUIApplication
    {

        protected override void OnCreate()
        {
            base.OnCreate();
            Initialize();
        }

        void Initialize()
        {
            Window.Instance.KeyEvent += OnKeyEvent;

            TextLabel text = new TextLabel("Hello Tizen NUI World");
            text.HorizontalAlignment = HorizontalAlignment.Center;
            text.VerticalAlignment = VerticalAlignment.Center;
            text.TextColor = Color.Blue;
            text.PointSize = 12.0f;
            text.HeightResizePolicy = ResizePolicyType.FillToParent;
            text.WidthResizePolicy = ResizePolicyType.FillToParent;
            Window.Instance.GetDefaultLayer().Add(text);

            Animation animation = new Animation(2000);
            animation.AnimateTo(text, "Orientation", new Rotation(new Radian(new Degree(180.0f)), PositionAxis.X), 0, 500);
            animation.AnimateTo(text, "Orientation", new Rotation(new Radian(new Degree(0.0f)), PositionAxis.X), 500, 1000);
            animation.Looping = true;
            animation.Play();
        }

        public void OnKeyEvent(object sender, Window.KeyEventArgs e)
        {
            if (e.Key.State == Key.StateType.Down && (e.Key.KeyPressedName == "XF86Back" || e.Key.KeyPressedName == "Escape"))
            {
                Exit();
            }
        }

        static void Main(string[] args)
        {
            var app = new Program();
            app.Run(args);
        }
    }
}

Running it through a TV emulator, it works. My goal, however, is to have it call some C++ functions. For that, I had another program that generated a .dll using Visual Studio as well.

I simply need this header file:

//Header.h
#pragma once

#ifdef CPPPROGRAM_EXPORTS
#define CPPPROGRAM_API _declspec(dllexport)
#else
#define CPPPROGRAM_API _declspec(dllimport)
#endif

// Simple greeting function
extern "C" CPPPROGRAM_API void message();

// Adds two numbers
extern "C" CPPPROGRAM_API int add(int a, int b);

// Says hello to passed parameter
extern "C" CPPPROGRAM_API void greet(char* name);

which is linked to the actual .cpp file that implements the logic:

#include "pch.h"
#include "Header.h"
#include <stdio.h>

// Testing basic printf function
void message() {
    printf("Hello, from C++!\n");
}

// Testing basic parameter passing
int add(int a, int b) {
    return a + b;
}

// Testing slightly complicated array passing (rip structs and objects)
void greet(char* name) {
    printf("Hello, %s!", name);
}

Running and building it, it results in a .dll file: ...\TizenDotNetApp\x64\Debug\CppLibrary.dll

Copy always property

I then added it to my Tizen app's solution and made sure its properties are "Copy always". Then, I modified the Tizen .NET app to actually call the .dll:

using System;
using Tizen.NUI;
using Tizen.NUI.BaseComponents;

using System.Runtime.InteropServices;

namespace TizenDotNetApp
{
    class Program : NUIApplication
    {

        [DllImport("CppLibrary.dll")]
        static extern int add(int a, int b); // <-- called the function


        protected override void OnCreate()
        {
            base.OnCreate();
            Initialize();
        }

        void Initialize()
        {
            Window.Instance.KeyEvent += OnKeyEvent;

            int result = add(5, 8); // <-- simple adding here

            TextLabel text = new TextLabel("Hello Tizen NUI World");
            text.HorizontalAlignment = HorizontalAlignment.Center;
            text.VerticalAlignment = VerticalAlignment.Center;
            text.TextColor = Color.Blue;
            text.PointSize = 12.0f;
            text.HeightResizePolicy = ResizePolicyType.FillToParent;
            text.WidthResizePolicy = ResizePolicyType.FillToParent;
            Window.Instance.GetDefaultLayer().Add(text);

            Animation animation = new Animation(2000);
            animation.AnimateTo(text, "Orientation", new Rotation(new Radian(new Degree(180.0f)), PositionAxis.X), 0, 500);
            animation.AnimateTo(text, "Orientation", new Rotation(new Radian(new Degree(0.0f)), PositionAxis.X), 500, 1000);
            animation.Looping = true;
            animation.Play();
        }

        public void OnKeyEvent(object sender, Window.KeyEventArgs e)
        {
            if (e.Key.State == Key.StateType.Down && (e.Key.KeyPressedName == "XF86Back" || e.Key.KeyPressedName == "Escape"))
            {
                Exit();
            }
        }

        static void Main(string[] args)
        {
            var app = new Program();
            app.Run(args);
        }
    }
}

Results, however, are unfortunate:

Unfavorable results

Ignore the .dll name though. I've been changing and modifying it to see if anything works, but nope. The output warning always remains the same: it somehow cannot find the .dll file despite being referenced already.

The result is different when I try a simple C# console app, though; it is able to recognize the .dll file and call the C++ functions in C# flawlessly.


Solution

  • Found the answer (thanks to @swift-kim). The architecture of the TV, emulator, and PC that's compiling the .DLL is different.

    In fact, the TV and emulator is using a form of Linux, so you would actually need a .so (Linux) and not a .dll (Windows) file.

    Instead of using g++ or CMake to compile it normally (which will base the output .so/.dll on your own machine's architecture), use either g++-arm-linux-gnueabi (.so compiler for the TV) or g++-i686-linux-gnu (.so compiler for x86 emulator)

    The command to generate a .so should look something like this:

    arm-linux-gnueabi-g++ -fPIC -shared calculate.cpp -o libcalculate.so (yep, the command has the g++ at the end for some reason)

    where your output (-o) is libacalculate.so, and the original file you want to convert is calculate.cpp. This will work with the TV as long as you make sure the normal properties of adding an existing file is correct ("Copy Always" property is on, etc.)