10

This is a little bit difficult because I don't even know if my C++ is well implemented.

I want to call a function from Unity3D which I pass some parameters such float *points and my C++ writes in that pointer.

Well, starting from the C++ part, I've written:

main_function.cpp this is my main function in C++ which works perfectly as binary, for example.

#include "main_function.h"

extern "C" void getPoints (uchar *data, float *points, int rows, int cols, const char *trackername) {
    //load detector model
    face_tracker tracker = load_ft<face_tracker>(trackername);

    //create tracker parameters
    face_tracker_params p; p.robust = false;
    p.ssize.resize(3);
    p.ssize[0] = Size(21,21);
    p.ssize[1] = Size(11,11);
    p.ssize[2] = Size(5,5);

    Mat im = Mat(Size(cols, rows), CV_8U, data);

    if(tracker.track(im,p))
        tracker.draw(im, points);

}

main_function.h

#include "opencv_hotshots/ft/ft.hpp"
#include "opencv2/highgui/highgui.hpp"
#include <iostream>

extern "C" {
    void getPoints (uchar *data, float *points, int rows, int cols, const char *trackername);
}

Then I want to wrap my C++ code to C#, so I make the:

AEDwrapper.h

// AEDwrapper.h
#pragma once

#ifdef TESTFUNCDLL_EXPORT
#define TESTFUNCDLL_API __declspec(dllexport) 
#else
#define TESTFUNCDLL_API __declspec(dllimport) 
#endif

using namespace System;
#include "stdafx.h"
#include "C:\Users\Rafael\Desktop\AEDlibrary\main_function.h"
extern "C" {
    namespace AEDwrapper {

        TESTFUNCDLL_API public ref class AED
        {
            void getPointsAED (uchar *data, float *points, int rows, int cols, const char *trackername);
        };
    }
}

and AEDwrapper.cpp

// Archivo DLL principal.    
#include "stdafx.h"
#include <ctime>
#include <iostream>
#include <chrono>
#include <sys/timeb.h>

#include "AEDwrapper.h"

using namespace std::chrono;

extern "C" {
    void AEDwrapper::AED::getPointsAED (uchar *data, float *points, int rows, int cols, const char *trackername){
        getPoints(data, points, rows, cols, trackername);
    }
}

I build it and it becomes in a AEDwrapper.dll.

Now in Unity3D, in the C# part (script) I try to do:

[DllImport ("/Assets/plugins/AEDwrapper.dll")]   
// or [DllImport ("AEDwrapper")]
private static extern unsafe void getPointsAED (byte* data, float* points, int rows, int cols, sbyte* trackername); 
//DECLARA METODO DEL DLL

DllNotFoundException: /Assets/plugins/AEDwrapper.dll

I know I could be wrong in early steps from my code, but have you ever done that before??? I'm kind of lost.

Thank you in advance.

Rafael.


EDIT:

I've tried with a simple function (for example: int gimmetwo(); in the header and:

int gimmetwo() {
    return 2;
}

and the result is the same :(

EDIT !!!! 11 July

After seeing answers like @k-gkinis and @nikola-dimitroff, I've understood that I have to compile different libraries for different environments.

In this case, I've created a Plugin.bundle for Mac OS x with:

Plugin.pch:

extern "C" {
    string getmytext();
}

Plugin.cpp

#include "Plugin.pch"
string getmytext() {
    return "weowoewoeowoew";
}

I built it and I imported it to Unity3D:

[DllImport ("AED")]
private static extern string getmytext ();

static void obtenerPuntos()
{
    Debug.Log (getmytext());
}

but I still get the same error !!

enter image description here

The plugin is in the right place I guess

enter image description here

What's wrong?

Rafael Ruiz Muñoz
  • 5,333
  • 6
  • 46
  • 92
  • can you add full path for the dll? is look like problem with the file itself... – Proxytype Jul 05 '15 at 06:41
  • stupid question but , you have placed the dll in the plugins folder right ? – Uri Popov Jul 05 '15 at 12:35
  • Yes, http://snag.gy/I4w9q.jpg – Rafael Ruiz Muñoz Jul 05 '15 at 12:47
  • what platform are you compiling to? maybe also "Plugins" must start with a uppercase "P" – JeanLuc Jul 05 '15 at 14:28
  • Nothing happened as well with the uppercase P (script and Scene). I'm compiling the DLL with Visual Studio in a Windows 8 inside a VirtualBox – Rafael Ruiz Muñoz Jul 05 '15 at 14:40
  • I think that if you're using the plugins folder, you should just do [DllImport ("PluginName")] not the path. Check this out: http://ericeastwood.com/blog/17/unity-and-dlls-c-managed-and-c-unmanaged – RaidenF Jul 07 '15 at 09:02
  • It's already commented on the code. Means that it has been tried – Rafael Ruiz Muñoz Jul 07 '15 at 09:13
  • I only wrote plugins for iOS and Android. I would suggest to try out the simplest plugin package from [Building Plugins for Desktop Platforms](http://docs.unity3d.com/Manual/PluginsForDesktop.html) (download link at the end). This should work on every Unity installation. Then check out what are the differences – Kay Jul 07 '15 at 11:37
  • @Kay thanks for your reply. I'm interested in make it work for Multiplatform, but my main interest is Android and iOS at the moment... can't I do it from a simple DLL ? (or maybe from source code as well?) – Rafael Ruiz Muñoz Jul 07 '15 at 11:43
  • @RafaelRuiz You can't use a native Windows dll on Android / iOS. A native .dll has an entirely different format than .NET dlls even though they use the same extension and they don't run on any other platform. You need to compile your CPP file specifically for Android and iOS. VisualStudio2015 has support for that, see https://msdn.microsoft.com/en-us/library/dn872463(v=vs.140).aspx – Nikola Dimitroff Jul 07 '15 at 12:35
  • for iOS take a look at my answer here how to write a tiny native plugin: http://stackoverflow.com/a/30071670/1032658 – JeanLuc Jul 07 '15 at 14:04
  • @NicolaDimitroff since I've never done this, is there any way to debug that I'm calling the right function when exporting to Android? Or I need to build and install everyone I want to try? Thank you. – Rafael Ruiz Muñoz Jul 07 '15 at 15:28
  • If you want to use `*char` etc you need to use `IntPtr` in your c# class. basic `float`,`int` etc is ok but `*char` like needs `IntPtr`. Secondly don't wrile extension of dll. Use like that `[DllImport ("AEDwrapper")]` – Barış Çırıka Jul 08 '15 at 06:33
  • Unfortunately, due to the way that platforms are, plugins must be compiled for each different platform, and included in your release. So for a desktop, ios and android release, you need 3 different builds of the same C++ code. According to unity's manual: "For cross platform deployment, your project should include plugins for each supported platform (ie, libPlugin.so for Android, Plugin.bundle for Mac and Plugin.dll for Windows). Unity automatically picks the right plugin for the target platform and includes it with the player." http://goo.gl/pgmWrq – RaidenF Jul 08 '15 at 15:01
  • @K.Gkinis I've updated the question – Rafael Ruiz Muñoz Jul 11 '15 at 17:05

1 Answers1

5

As seen here, make sure that you have the correct options in the inspector for the plugin.

Also, because you're targetting iOS, you must statically link the plugin, so your import attribute should be:

[DllImport ("__Internal")]

you could write

   #if UNITY_IPHONE || UNITY_XBOX360

   [DllImport ("__Internal")]

   #else

   [DllImport ("PluginName")]

   #endif

Note from the manual:

"iOS native plugins can be called only when deployed on the actual device, so it is recommended to wrap all native code methods with an additional C# code layer. This code should check Application.platform and call native methods only when the app is running on the device; dummy values can be returned when the app runs in the Editor."

So:

private static extern string getmytext();

public static string getmytextWrapper()
{
        if (Application.platform != RuntimePlatform.OSXEditor)
               return getmytext();
        else
               Debug.Log("Can't call native iOS plugin on other platforms.");
       return string.Empty;
}

and then call getmytextWrapper from somewhere in your code.

(I don't have xcode, so I can't help you much on ios)

PS The DLLImport goes above the snippet that starts with private static extern

Community
  • 1
  • 1
RaidenF
  • 3,411
  • 4
  • 26
  • 42
  • just one question... if I'm building a Plugin.bundle, I'm building for OSXEditor, so it should work for the case `Application.platform == RuntimePlatform.OSXeditor`, doesn't it? – Rafael Ruiz Muñoz Jul 11 '15 at 18:51
  • Unity3D is saying `EntryPointNotFoundException: getmytext` when I put `==` in your condition, because I'm using Mac OSx, but anyway I built it for iPhone, and compiled with XCode and it said: > Undefined symbols for architecture armv7: "_getmytext", referenced from: RegisterMonoModules() in RegisterMonoModules.o – Rafael Ruiz Muñoz Jul 11 '15 at 19:09
  • 1
    Damn that's complicated xD. Ok 1st for Iphone, you should do if (Application.platform == RuntimePlatform.IPhonePlayer) . Apart from that, crazy idea, try renaming string getmytext() { to string _getmytext() { in the c++ file. Also, check this, keep in mind that unity5 doesn't need the iOS folder or the plugins folder, just the settings in the inspector: http://blog.mediarain.com/2013/03/creating-ios-plugins-for-unity/ – RaidenF Jul 11 '15 at 19:19
  • Same thing, maybe the code is not 100% correct?? is that OK to have a Plugin.bundle and two files with `.pch` and `.cpp` extension ?? This is going to be impossible :( anyway I'm awarding the bounty because at least I can get the plugin read, but not the function. If you realize some error in my last code (`getmytext()`) let me know :) – Rafael Ruiz Muñoz Jul 12 '15 at 11:31
  • How can I do this in windows? – Madhuparna Bhowmik Jun 09 '19 at 17:24