Loading a native C++ dll generated from MATLAB(Simulink) into Unity3d - c++

I am a game developer working on a serious game. I have some data simulation taking place as a result of a MATLAB (Simulink) model, that was created by someone who left the team now. All this data simulation generates useful data and allows me to query and check variables when needed. I needed to build a game using this model. So I used the Simulink Code generator to generate the code for my model in C++. This is native C++ and is procedural. The volume of code is high for me to rewrite it, hence I am refraining from doing that. I need to use this code in Unity3d, the engine I am developing the game on.
Long story short. I need to load a native C++ dll (generated by Simulink) in Unity3d.
What I tried:
I tried using the Unity3d's native plugin API. I have pro version and it doesn't seem to detect the dll, and just throws exceptions. I am using the extern keyword to make the required variables public, still no luck.
I tried following this tutorial (http://blogs.abo.fi/alexeevpetr/2011/11/18/simplified-building-simulink-generated-c-code-in-visual-studio/) , but it throws errors and doesn't build, maybe that's because of the version of MATLAB.
I also considered using a wrapper, however that would imply me rewriting most of the code again.

I've never used native dlls in Unity, but you could always try one of the several code bridging methods to call C++ code from C#, I guess. So how about writing a C++/CLI wrapper? It won't force you to rewrite anything. It gives managed access to your unmanaged code, and it's a useful technique to learn anyway.

You should be able to load your native plugin into Unity3D, even if it requires MATLAB libraries (Just make sure they're also in the plugins directory). I recently answered a similar question around this, as it can be fairly tricky to get right. I would suggest you check it out HERE, and modify your question with specific errors and problems you're having trying to loading the native code.

From Geomorillo on U3d forums:
Before anything,
1) install Visual C++ Studio Express 2010 we need the sdk from .NET for compiling, (NOTE:Maybe you can use visual C# express instead for compiling because it require the .NET sdk but no sure )
2)You must setup matlab with the command "mbuild - setup", and choose the compiler Microsoft Visual C++ Studio Express 2010
3) you must have a function already created and saved to a ".m" file mine is called mycos.m here is its contents:
function a=mycos(b)
a=cosd(b);
end
where "a" is the return parameter and "b" the input parameter, it is important to know how many return parameter you have in this case 1 (see step 12)
4) use the "deploytool" command, a window should open, name the project "simplelibs" any name should do, choose a location c:\matlab\simplelib, choose in type .NET Assembly, OK
5) After that new options int form of tabs should appear to the right of your window, the Build and Package Tabs.
In the Build tab you should add a class with the Add class option, it will automaticly was named Class1, but i changed it to Myclass, here you can add your functions to your class using Add files, i've added mycos.m
6) You should have noticed 3 buttons next to the project name, click the 3rd one with the shape of a nut, go to Settings a new window should appear, go to .NET tab and in the Microsoft Framework choose 3.5 to make sure you are using .net 3.5 for compiling(required for unity3d)
7) we are ready to compile, do so with the 1st button, it should take a while....
8) After compiling without errors, the files are in the distrib folder inside your project path , open unity and create a new project. copy the 2 dlls into the root inside unity.
9) Locate de directory "dotnetbuilder" inside "c/.../matlab/../toolbox" copy or drag it all its contents to your unity project.
10) We need the a dll MWArray.dll because when compiling our libraries matlab wraps our function in an Array and it use its methods to access our functions im not gonna explain this, google it please, normally it can be found inside matlab installation dotnetbuilder/bin/win32/2.0/ but since you have copied it to unity dont copy again, when using this mwarray i found a bug with monodevelop in this library so i had to decompile it and fix the bug i've to recompile it again :) you you can download this file here https://dl.dropbox.com/u/6716823/MWArray.dll and replace the one found inside unity project (do not!!! replace the original from matlab directory)
11) create a c# script and asign it to main camera or any object in scene
here is its contents
using UnityEngine;
using System.Collections;
using System;
using MathWorks.MATLAB.NET.Arrays; // import from MWArray.dll
using simplelib;
public class myMatlab : MonoBehaviour {
void Start () {
simplelib.Myclass g = new simplelib.Myclass();
Debug.Log(g.mycos(1,95).GetValue(0));
}
}
12) g.mycos(1,95); // remember when i said it wraps your function !!! the first parameter is the number of parameters returned from our matlab function in this case 1, the 95 is the parameter we want to send to our function, we get an array we can access it with .GetValue(0)
13) play and enjoy
This is an example with a simple function so i dont know if it will work with a more complex program
i hope this works for you

Related

Modifying/Adding Side-By-Side Assembly search sequence

This question is a bit similar to this one, except for a little twist :
Can I modify the side-by-side assembly search sequence?
We have a couple different softwares, made with different languages, that talk to each other when they run. To achieve this we made .NET COM objects that we load using Registration-Free COM Activation. This works well. Some of the languages we use can't load COMs, so we made a C++ Wrapper DLL that uses ACTCTX to activate the COMs from their embeded manifests. Also working well.
But now, we have a case where our C++ Wrapper is loaded by code that is ran by an application that isn't ours (let's call it the runtime) that is located somewhere and our application is located somewhere else. We'd rather deploy our COM objects at the same place as application is deployed rather than next to the runtime application.
Not that it is important as the concept remains the same, but the runner is FourJ's Genero (fgl.exe) and the code that calls our C++ wrapper are in .42m files. The runner (fgl.exe) is installed with Genero, by default in Program Files\FourJs and our applications are in another directory with our company's name ie : Program Files\MyCompany
This is similar to what you'd get with Java. Runtime at one place, applcation somewhere else.
So in our case, our .42m loads the C++ Wrapper properly, the wrappers activates the COM (located in the same directory as our .42m and the wrapper) properly but once we try to instanciate an object, we get a "80070002" file not found error.
I've read
Assembly Searching Sequence and noticed the described behavior using Process Monitor.
So what happens is, since ultimately it's fgl.exe that is running, the Windows Side-By-Side loader looks into :
C:\Program Files(x86)\FourJs\fgl\gen2.50\bin\MyCom.dll
C:\Program Files(x86)\FourJs\fgl\gen2.50\bin\MyCom.dll\MyCom.dll
While my COM is really inside of C:\Program Files(x86)\MyCompany\MyApplication\MyCom.dll
To confirm the behavior, we copied the COM in the same directory as fgl.exe and as expected, it works.
So i would like to be able to add a Search Directory to my Activation Context so that it looks for this DLL in my deployment directory.
Is this possible ?
If i can't find another solution, we'll end up deploying our COMs inside of that directory, but that's just not the right.
Thanks

Beginners qestion: How to import / access a .NET assembly from a Visual Studio 2008 C++ ATL project?

I'm just taking my first steps in the Visual Studio 2008 / C++ world, and I do so by trying to create a new CTI Connector for Salesforce. I managed the first part without too much hassle, so now I have an almost-functional CTI Connector. There's only one, but vital part missing: The actual connection to the Call Center system.
The manufacturer provides a .NET integration DLL that also provides a COM interface. I've successfully used the COM part before in Delphi (my native environment...) and I wouldn't mind to use the COM approach here as well, though using the .NET interface seems a bit more natural to me.
Now I do have an ATL project created in Visual Studio 2008 SP1, providing a COM interface to the Salesforce side of the connection.
I do also have a .NET dll providing the interface to the Call Center, and a registered COM object that does the same.
What I don't have is the slightest idea how to get this into my C++ project.
From my Delphi experience I was expecting Visual Studio to have some Import feature that automagically builds a class around the integration object in order for me to simply use it, but obviously there isn't, at least not for ATL projects. Changing the project type to something else is currently not an option, as this is the documented way to interface Salesforce.
I found some hints to simply include the .tlb in a .cpp file in order to use the COM object, and doing so does indeed help IntelliSense to recognize the Namespace and Classes of this object, but this is where I'm stuck.
So my qustions are:
Am I required to create the methods and events provided by the .NET dll / COM object manually, or is there a simpler way to get them automatically?
If manual creation is required, how do I access the Event interface of the integration object?
How do instantiate the integration object, and do I have to do so at all?
Until now, I've created a class called CAgentIntegration. In the .cpp file I import the typelib provided with the DLL (AgentIntegration.dll and AgentIntegration.tlb), both files are present in the source folder of my project.
In the constructor of CAgentIntegration, I try to somehow access the imported object. IntelliSense obviously recognizes the Namespace AgentIntegration, because it offers the AgentClient class as code completion. It is the part after AgentClient of which I have no idea. The example below clearly doesn't work because the compiler complains that to the left of -> a class or struct is required.
#include "StdAfx.h"
#import "AgentIntegration.tlb"
CAgentIntegration::CAgentIntegration(void)
{
AgentIntegration::AgentClient->Initialize();
}
CAgentIntegration::~CAgentIntegration(void)
{
}
The following image is from Object Browser in Visual Studio, after adding the .tlb to it. Maybe this helps to better understand how things are arranged inside the DLL.
Please bear in mind that this is a qustion from someone who doesn't even know the correct syntax to include the integration object into the project, so the answer may be way less complex than you may assume - it would probably be enough to just provide a short code sample that I can use as a template to start from. On the other hand, "just use #import" as an answer would not help me much because I don't know how to use it ;-)
Thanks in advance
Patrick

Can't see variable contents when debugging C++ code called from a managed app

I've got some native C DLLs which I'm calling from a Managed C++ Class library ("Rem"). In the "Rem" class library I've got one native C++ class (api) and one managed C++ class (API).
The managed class (API) is called from a C# console application for now (will be used in a web application later).
When debugging I can step through my native code just fine.
My problem is that when I'm debugging, I can't see the values of any variables other than simple types that are locally declared.
Function parameters are not available in the debugger and if I try to add them as a Watch it just says "error: identifier 'schema_name' out of scope" ('schema_name' is the variable name)
Any structs just show the value "{...}", both in the quick watch and the Watch-window.
If I try and add a watch to a field in a struct I get the value "error: 'entryList.numItems' does not exist"
Stuff I've tried:
I've tried creating a Console application in Managed C++ and debug from that, same thing.
I tried unchecking the
Tools->Options->Debugging->General->Managed C++ Compatibility Mode, then I couldn't step into the code at all (no symbols loaded for the breakpoints)
In the C# console app project, I've gone into Properties->Debug and checked "Enable native code debugging" (and unchecked it)
In the C++ class library I've gone into Properties->Debugging->Debugger Type and tried "Mixed", "Native", "Managed" and "Auto".
Any suggestions as to what I'm doing wrong?
I guess you are using Visual Studio 2012 Update 2. In that case - this is a known bug with Update 2:
https://connect.microsoft.com/VisualStudio/feedback/details/783004/children-cannot-be-evaluated-on-c-cli-after-vs2012-update-2
Be careful though, the "workaround" of uninstalling Update 2 will leave you with a broken Visual Studio as seen in this bug-report (yes, Update 2 is broken):
https://connect.microsoft.com/VisualStudio/feedback/details/785396/uninstalling-vs2012-update-2-and-repair-of-vs-results-in-atl-files-missing
In case you are not using Update 2 this might not be the correct answer but it could help others who experience exactly this problem using Update 2.

MFC add Typelib or ActiveX for OPOS

So at work I have been working for a few months on a OPOS driver for a few different things. I didn't create the project, but I have taken it over and am the only one developing it. So today I got curious about the way that it was done and I think that it may have started off on the wrong foot. I had to do a little bit of digging to find out that it uses the OPOS drivers from a company called MCS (Monroe Consulting Services) I downloaded 1.13 and installed the MSI version. I fired up VS created a new mfc dll. I then went to add a class. This is where I am confused.
It doesn't matter if i choose Typelib or ActiveX it usually gives me the same list of interfaces that I can add/extend from(with one exception that comes to mind with MSR it has an events interface that I can extend) And they both make the same header file (in the case with msr it is COPOSMSR.h) but one extends CCmdTarget, and the other extends CWnd. This is my first question. Which should I choose? what is a typelib/ what is a ActiveX component and how do they differ from one another.
The one i've been working on extends CCmdTarget. For the life of me I can not figure out how the driver knows to use one of the files (USNMSRRFID) but that is where all the development went into. (I broke it up a bit so it wasn't just one huge file) But that file doesn't extend COPOSMSR..it extends CCmdTarget as well. The only time i see anything mention the USN file is in MSRRFID.idl (which confuses me even more) Any one have clarity for this?
Part of me thinks this could make a very big impact when it comes time to deploy. A few of the test apps that have been written that make use of this driver require a somewhat confusing setup process that involves registering different drivers, copying files into a specific folder, setting up the registry and so forth. I think that if i can get a grip on what this all means and how to make a nice application that extends one of these OPOS devices properly that I could save my self further grief in the future.
Any tips or pointers??? Sorry if it is a newb question..but i am new to C++. I started with Java then moved to C# so some of this stuff is WAY over my head....
Well so I've done TONS of digging, and it is like searching for dinosaurs. Not easy, and hard to find. I will end up writing a nice little how to on this, but for now I will put up my findings. Although I still don't have this 100% i know I am close.
Turns out the typelib and activeX things are not a big concern but come into play after you've gotten started. ActiveX is for Control objects, and Typelib is for the Service Object. The most important thing is to get started correctly. I found a article on some Chinese website that offers some OK tips after figuring out the translation errors. To start with you will want to make a C++ project with Automation. It can be ATL or MFC. My preference is MFC. In the UPOS 1.13 pdf (or newer) in Appendix A section 8 it describes the responsibilities of the Service object. It has the main methods you need to implement. There are 16 methods you have to add, and at least 4 methods that get/set the properties for your OPOS device.
So to get started you will need to open up the add class wizard (for MFC classes) and click Add MFC class. You wil want your base class to be CCmdTarget. Come up with a classy Class name (I chose PinpadSOCPP) Then in the automation radio buttons select Creatable by type ID. It should fill in your type id as [Project Name].[Class name] so mine was PinpadSO.PinpadSOCPP. hit finish. This makes a nice interface file that you can use Class view to add methods and so forth to it.
As for adding the methods there are 2 things to note about this, and one of them I haven't figured out 100% yet. The first is that you have to implement all the methods in that section with the correct parameters and return values. Most of them return LONG (32bit signed number). and the 2 most common parameters are LONG and BSTR. (there is the occasional pointers for when you have "out" parameters) This is the part that I think that I am currently failing as I don't know if I have them all implemented correctly and that is why I am getting error 104/305 (which from the Chinese article says that I am missing something from my methods) I'm not sure if it is case sensitive, and I'm not sure of the 7 properties that look to need to have get/set which ones need to be implemented because the MSR SO that i am working on from work doesn't use them all and that SO is working. The other is that after you implement the base OPOS methods you have to also implement the extra methods from your specific OPOS device. Since I am doing PINPad there are 6 additional methods I have to implement.
Now this is a lot of time consuming work because you have to open up class view, navigate to the name of your project class. Expand it and go to the Interface portion. My Project name is PinpadSO, and the file that I am implementing this in is PinpadSOCPP (which means the interface name is IPinpadSOCPP) right click on IPinpadSOCPP and click add > add method. This brings you to a 2 step process. You fill in your return value, name of your function, add in all your parameters. Hit next and fill out some help string info (if you want) and hit finish. Now after you do that 20+ times it gets old and slow...and if you are like me you type Computer instead of Compute and flip flop letters, or forget to hit add on all your parameters. A person could make a nice little program to edit the 3 files that get changed each time you add a method and that would speed it up considerably. If you make a mistake you will need to open up [project name].idl, [class name].h, and [class name].cpp those are the 3 files that get the methods added to it directly. I recommend not making a mistake.
so now that all that hard work is out of the way. Compile your program. If you want to save your self an extra step you could turn on Auto Register in the linker project settings (NOTE: if you do that you'll need to run Visual Studio as admin if you program in vista or higher) this would save you of having to open a command window (admin) navigate to your DLL and use the command regsvr32 on that DLL. Nice thing is that you don't have to do that over and over again, just the once will do. I have no hard facts that it works like that every time but the MSR SO that I am working on, I'll make changes to it, compile it, then open up my OPOS tester program and the changes have taken affect.
After that you need to make your registry additions. navigate to HKLM\software\OLEforRetail\ServiceOPOS
(NOTE if you have a x64 machine you'll do this twice. One there, and again at HKLM\software\Wow6432Node\OLEforRetail\ServiceOPOS )
You'll need to add a Key for whatever OPOS device you are working with. I am making a pinpad SO so I made a Key called PINPad (check your UPOS document to see what name you should give it) Lastly choose a name for your device. I chose the model type of the from the vendor as my device name (C100) and made a sub key in PINPad. The default REG_SZ value needs to be your registered SO Device TypeID. in my case it is PinpadSO.PinpadSOCPP
if you don't have a OPOS test program (which I just made my own as a console program) then you can use the Microsoft OPOS test app (I couldn't get it to work on my x64 machine...but maybe you'll have better luck with it) If you do decide to make your own OPOS test app make sure you compile it for x86 machines (even if you have x64) OPOS does not like x64 for some reason (probably the pointers length I'd assume)..at any rate. Once you got it all setup run your test app (for my case I am just running OPOSPinpadClass pin = new OPOSPinpadClass(); Console.WriteLine(pin.Open("C100")); and hope for 0 :)
I am currently getting 104 (E_NOSERVICE)..and like i said before i think it is because I don't have all my methods correct. If that turns out to be the case I'll edit this response, or I'll report back and say what it really was.
Anywho, i hope this helps anyone else who decides they want to make their own SO. Good luck
UPDATE
OPOS checks a couple of properties when you call the Open command. One of the properties that is a must to implement is the in the GetPropertyNumber, and it is PIDX_ServiceObjectVersion. You will need to set this number to return (1000000 * majorVersion) + (1000 * minorVersion) + revision since I am making a OPOS 1.13 compatible SO my returned ServiceObjectVersion is 1013000. You will also want to implement 3 properties in GetPropertyString:
PIDX_DeviceDescription
PIDX_DeviceName
PIDX_ServiceObjectDescription
For all other values you can return a empty string or 0 until you start hooking all those things up.
As a side note if you don't want to make it in C++ you don't have to. You can make it in any language that you can write a ActiveX object in (such as a COM visible .NET class library)

How to use SAPI's SetNotifyCallbackFunction() in a CLR project with Windows Form as the interface window?

I'm trying to write a dll plugin for Winamp. I'm using Microsoft Visual Studio 2008 and Microsoft SAPI 5.1. I created the interface window using Windows Form (System::Windows::Forms::Form).
I tried to use SetNotifyWIndowMessage(), but the method is never called when I speak to the microphone. So I tried using SetNotifyCallbackFunction(), but I got a compile error saying that I should use '&' in front of the method name in the parameter. However, when I add the '&', I got another compile error saying that i can't take the address of the method unless creating delegate instance.
What should I do? Someone please help me..
Well, as indicated, you need to create a delegate instance to wrap your callback. But don't go there, SAPI 5.1 is quite outdated. Updates are no longer shipped because the .NET framework has a very nice wrapper for it. Check out the System.Speech.Recognition namespace and the SpeechRecognitionEngine class. You'll want to use the SpeechRegonized event. You'll find plenty of code samples in the MSDN Library pages for the class.