How to call GL.IssuePlugInEvent in Unity3d and pass parameters to the plugin side in C - unity3d

I'm trying to write a plugin for Unity that passes information between the native side of android (but same may apply to any other dll or so library) and the unity side. The information I want to share is OpenGL related. On Unity docs it's specified that everything that has to run on the rendering thread must be called through The GL.IssuePlugInEvent function. This function though is quite strict on the parameters: it needs a to call a function with a specific signature:
Callback must be a native function of "void UNITY_INTERFACE_API UnityRenderingEvent(int eventId)" signature
and has only the additional parameter eventId.
How can I then pass back on the unity side information from the so library?

The Unity examples for creating a plugin and using IssuePluginEvent cover the case where you want/need to call directly a C function, and this function accepts only an eventId as parameter. If the reader comes from a C\C++ background and is not familiar with C#, it may be misleading. In fact, you can actually call a C# function with this simple trick, and inside that function call your C functions passing multiple parameters.
The steps are:
get a function pointer for a C# function (notice that the function will be static)
pass that function pointer to GL.IssuePluginEvent
inside your static C# function, based on the case of eventId, call the appropriate C function
void Update()
{
GL.IssuePluginEvent(RenderThreadHandlePtr, GL_INIT_EVENT); // example
}
/// <summary> Renders the event delegate described by eventID. </summary>
/// <param name="eventID"> Identifier for the event.</param>
private delegate void RenderEventDelegate(int eventID);
/// <summary> Handle of the render thread. </summary>
private static RenderEventDelegate RenderThreadHandle = new RenderEventDelegate(RunOnRenderThread);
/// <summary> The render thread handle pointer. </summary>
public static IntPtr RenderThreadHandlePtr = Marshal.GetFunctionPointerForDelegate(RenderThreadHandle);
public const int GL_INIT_EVENT = 0x0001;
public const int GL_DRAW_EVENT = 0x0002;
/// <summary> Executes the 'on render thread' operation. </summary>
/// <param name="eventID"> Identifier for the event.</param>
[MonoPInvokeCallback(typeof(RenderEventDelegate))]
private static void RunOnRenderThread(int eventID)
{
switch (eventID)
{
case GL_INIT_EVENT:
glInit(par1, par2, par3); // C function with 3 parameters
break;
case GL_DRAW_EVENT:
glStep();
GL.InvalidateState();
break;
}
}
[DllImport("hello-jni")]
private static extern void glInit(int par1, int par2, int par3);
[DllImport("hello-jni")]
private static extern void glStep();

Related

How to use a C++ class with pure virtual function?

I was given a class with pure virtual function like the following:
class IRecordingHour{
public:
virtual int getData() const = 0;
}
Now, I have another class that uses the IRecordingHour class:
class ProcessRecordingHours {
public:
ProcessRecordingHours (IRecordingHour &);
proteted:
IRecordingHour & recordingHour;
}
I was told that I am not allowed to implement the IRecordingHour class (the one with the pure virtual function).
My question is: without implementing the IRecordingHour clas, how do I use it in the ProcessingRecordingHours? That is, how do I create an instance of the IRecordingHour and pass it to the constructor of the ProcessRecordingHours?
You should create a subclass of IRecordingHour and implement the method getData, like
class ARecordingHour : public IRecordingHour
{
public:
int getData() const override //override is valid from C++11
{
return 42;
}
}
And then you can do:
ARecordingHour arh{};
ProcessRecordingHours prh{arh}; //{}- Modern C++ initialization
You can find similar examples in a good C++ programming book, such as The C++ Programming Language
Though you equate them, your two questions are in fact quite different.
how do I use it in the ProcessingRecordingHours?
There is no particular problem in implementing ProcessingRecordingHours without implementing a subclass of IRecordingHour. You don't need to do anything special. You simply avoid relying on anything not declared by IRecordingHour, which is no different than you ought to do anyway.
how do I create an instance of the IRecordingHour and pass it to the constructor of the ProcessRecordingHours?
You cannot. A class with a pure virtual method cannot be directly instantiated. Your ProcessRecordingHours can be used in conjunction with classes that extend IRecordingHour, but if you are not permitted to create such a class then you cannot exercise those parts of your ProcessRecordingHours class that depend on an IRecordingHour.
Perhaps, however, you have misunderstood the problem. You may be forbidden from implementing IRecordingHour::getData(), but not from implementing a subclass that overrides that method with a concrete one. Such a subclass could be instantiable, and would be usable in conjunction with ProcessRecordingHours.
I think your teacher plan to inject an implementation of IRecordingHour into ProcessRecordingHours.
Also, you can't use that class unless you generate a stub for IRecordingHour or you implement one yourself with some dummy return values.
/// <summary>
/// in C# and interface can only contain virtual methods. so no need to say virtual.
/// </summary>
interface IRecordingHour
{
int getData();
}
class MockRecordingHour : IRecordingHour
{
public int getData()
{
//just return something. This will be enough to get ProcessRecordingHours to work
return 100;
}
}
/// <summary>
/// this class expects a IRecordingHour.
///
/// how we get a IRecordingHour depends on who's implementing it. You, some 3rd party vendor or another developer who's using this class that you've written.
///
/// Oh wait. Since you're building ProcessRecordingHours, you need a IRecordingHour to get against. You can use a mocking tool or create one yourself that returns some dummy data
/// </summary>
class ProcessRecordingHours
{
private IRecordingHour _recording;
public ProcessRecordingHours(IRecordingHour recording)
{
this._recording = recording;
}
public void DoSomething() {
Console.WriteLine("Recording Data: {0}", this._recording.getData());
}
}

How to get c++ class to communicate with Windows Form textbox

I am currently writing a program in C++/CLI. I have a Windows Form which acts as a user interface. Now what I want to do is to declare a separate c++ class and give it access to a textbox on the form.
The form is declared in the file MyForm.h
The class is defined by a header file and cpp file, lets call them myClass.cpp and myClass.h
The functionality of the program should be as follows : The program should go through all the serial ports that are currently available, then try to open them and poll them for data. If there is a good answer from the serial port then then it should end searching and keep connected to this port. So in this case myClass should check for serial ports and return the name of the desired port. I also want to be able to track the progress of the port searching thread in a textbox on the windows form. I could probably just include the port search into the initialization code of the form, but that would be really messy and would result in a large chunk of code in a single header file. This does not really seem reasonable.
I know that I cannot directly access the Windows form textbox and have to use an Invoke method, this is currently not the problem. The problem is that I really do not know how to get the two classes to communicate with each other. I have tried declaring a pointer to a MyForm object, but this does not seem to be working. I cannot seem to get header and cpp files to connect.
I'm sorry if this sounds confusing, I'll try to explain by example and also code.
Just for concept testing I made a really simple program that consists of a Windows Form and a class called simpleAdder.
//simpleAdder.h
#pragma once
#include "MyForm.h"
using namespace System;
using namespace simpleClassTest;
public ref class simpleAdder
{
private:
Int16 a;
Int16 b;
MyForm^ m_form;
public:
simpleAdder(Int16 x,Int16 y, MyForm^ form);
Int16 add (void);
};
Here is the cpp file for simpleAdder :
//simpleAdder.cpp
#include "MyForm.h"
#include "simpleAdder.h"
using namespace System;
using namespace simpleClassTest;
simpleAdder::simpleAdder(Int16 x,Int16 y, MyForm^ form){
a = x;
b = y;
m_form = form;
}
Int16 simpleAdder::add (void){
return a+b;
//Try to invoke the textbox method. This is not implemented yet.
}
So the idea is that I would have a managed pointer to an existing form and through this, I could access the form itself. The adder class should basically just try to write the result of the x+y onto the form textbox.
Here is some code from the MyForm.h file
#pragma once
#include "simpleAdder.h"
namespace simpleClassTest {
using namespace System;
using namespace System::ComponentModel;
using namespace System::Collections;
using namespace System::Windows::Forms;
using namespace System::Data;
using namespace System::Drawing;
//ref class simpleAdder;
/// <summary>
/// Summary for MyForm
/// </summary>
public ref class MyForm : public System::Windows::Forms::Form
{
public:
MyForm(void)
{
InitializeComponent();
this->m_add = (gcnew simpleAdder (16,10));
//
//TODO: Add the constructor code here
//
}
protected:
/// <summary>
/// Clean up any resources being used.
/// </summary>
~MyForm()
{
if (components)
{
delete components;
}
}
private:
/// <summary>
/// Required designer variable.
/// </summary>
simpleAdder^ m_add;
private: System::Windows::Forms::Button^ button1;
private: System::Windows::Forms::TextBox^ textBox1;
System::ComponentModel::Container ^components;
//Here follows the automatically generated code.
The problem is that no matter what I do, I cannot get this to compile. The compiler does not recognize the MyForm type variable. Also having two headers that include each other does not seem right, but I really don't know what else to do. I tried declaring both classes in the same namespace, but that did not help either. Then I tried forward declaring the simpleAdder class in the MyForm header file, but that did not work.
I am obviously not experienced in c++/cli and it seems that I am doing something fundamentally wrong. I think there must be a better way to implement something like this. I mean in the end I would have to add other classes to the windows form to display information etc. There must be an easy way of doing this. Any help on this would be much appreciated.
Lets look at order of includes:
simpleAdder.cpp include MyForm.h
MyForm.h include simpleAdder.h
Inside simpleAdder.h include to MyFrom.h is skipped becose #pragma once
Then there is code:
public ref class simpleAdder
{
private:
Int16 a;
Int16 b;
MyForm^ m_form;
public:
simpleAdder(Int16 x,Int16 y, MyForm^ form);
Int16 add (void);
};
but there wasn't MyForm declared anywhere.
Read about forward declaration. You can declare MyForm before simpleAdder:
public ref class simpleAdder; // or without public

Publish an Event without PayLoad in Prism EventAggregator?

Why can't we Publish Events without any PayLoad.
_eventAggregator.GetEvent<SelectFolderEvent>().Publish(new SelectFolderEventCriteria() { });
Now, I don't need any pay load to be passed here. But the EventAggregator implementation mandates me to have an empty class to do that.
Event:
public class SelectFolderEvent : CompositePresentationEvent<SelectFolderEventCriteria>
{
}
PayLoad:
public class SelectFolderEventCriteria
{
}
Why has Prism not given a way to use just the Event and publish it like
_eventAggregator.GetEvent<SelectFolderEvent>().Publish();
Is it by design and I don't understand it?
Please explain. Thanks!
Good question, I don't see a reason for not publishing an event without a payload. There are cases where the fact that an event has been raised is all information you need and want to handle.
There are two options: As it is open source, you can take the Prism source and extract a CompositePresentation event that doesn't take a payload.
I wouldn't do that, but handle Prism as a 3rd party library and leave it as it is. It is good practice to write a Facade for a 3rd party library to fit it into your project, in this case for CompositePresentationEvent. This could look something like this:
public class EmptyPresentationEvent : EventBase
{
/// <summary>
/// Event which facade is for
/// </summary>
private readonly CompositePresentationEvent<object> _innerEvent;
/// <summary>
/// Dictionary which maps parameterless actions to wrapped
/// actions which take the ignored parameter
/// </summary>
private readonly Dictionary<Action, Action<object>> _subscriberActions;
public EmptyPresentationEvent()
{
_innerEvent = new CompositePresentationEvent<object>();
_subscriberActions = new Dictionary<Action, Action<object>>();
}
public void Publish()
{
_innerEvent.Publish(null);
}
public void Subscribe(Action action)
{
Action<object> wrappedAction = o => action();
_subscriberActions.Add(action, wrappedAction);
_innerEvent.Subscribe(wrappedAction);
}
public void Unsubscribe(Action action)
{
if (!_subscriberActions.ContainsKey(action)) return;
var wrappedActionToUnsubscribe = _subscriberActions[action];
_innerEvent.Unsubscribe(wrappedActionToUnsubscribe);
_subscriberActions.Remove(action);
}
}
If anything is unclear, please ask.
Just to update the situation since this question was asked/answered, as of Prism 6.2, empty payloads are now supported in Prism PubSubEvents.
If you're using an older version, this blog shows how to create an "Empty" class that clearly indicates the intent of the payload: https://blog.davidpadbury.com/2010/01/01/empty-type-parameters/

Cast error on SQLDataReader

My site is using enterprise library v 5.0. Mainly the DAAB. Some functions such as executescalar, executedataset are working as expected. The problems appear when I start to use Readers
I have this function in my includes class:
Public Function AssignedDepartmentDetail(ByVal Did As Integer) As SqlDataReader
Dim reader As SqlDataReader
Dim Command As SqlCommand = db.GetSqlStringCommand("select seomthing from somewhere where something = #did")
db.AddInParameter(Command, "#did", Data.DbType.Int32, Did)
reader = db.ExecuteReader(Command)
reader.Read()
Return reader
End Function
This is called from my aspx.vb like so:
reader = includes.AssignedDepartmentDetail(Did)
If reader.HasRows Then
TheModule = reader("templatefilename")
PageID = reader("id")
Else
TheModule = "#"
End If
This gives the following error on db.ExecuteReader line:
Unable to cast object of type 'Microsoft.Practices.EnterpriseLibrary.Data.RefCountingDataReader' to type 'System.Data.SqlClient.SqlDataReader'.
Can anyone shed any light on how I go about getting this working. Will I always run into problems when dealing with readers via entlib?
I would be careful with this implementation.
There is a thread on the Enterprise Library Codeplex site that explains the backgound for this:
http://entlib.codeplex.com/Thread/View.aspx?ThreadId=212973
Chris Tavares explains that it's not good to just return the .InnerReader, because then the connection tracking by Enterprise Library is thrown off (his response from May 20, 5:39PM):
"That approach will completely screw up your connection management. The whole reason for the wrapper is so that we could execute extra code to clean stuff up at dispose time. Grabbing the inner reader and throwing out the outer will leak connections!
"
So yes, this is a bit of a pain to deal with, we're in the same situation.
Regards,
Mike
ExecuteReader in Enterprise Library wraps IDataReader into RefCountingDataReader that as SqlDataReader implements IDataReader interface.
RefCountingDataReader has InnerReader property that you can cast to SqlDataReader. The sample below is in C# but you can easily convert it to VB.NET.
SqlDataReader reader;
reader = ((RefCountingDataReader)db.ExecuteReader(command)).InnerReader as SqlDataReader;
if (reader != null)
reader.Read();
return reader;
Hope it helps
I am having leaking connections because all my DA methods require a SqlDataReader.
Now I have to return the inner RefCountingDataReader and can never close the outer reader.
The old Enterprise Library was working fine with returning a SqlDataReader.
I've taken into account the comments and code posted by ctavars at http://entlib.codeplex.com/discussions/212973 and http://entlib.codeplex.com/discussions/211288, resulting in the following generic approach to obtaining an SQL data reader.
In general you use IDataReader in the using statement, then use that reference directly when you can. Call AsSqlDataReader on it when you need something SQL-specific.
Add this extension class somewhere:
/// <summary>
/// Obtains an <see cref="SqlDataReader"/> from less derived data readers in Enterprise Library
/// </summary>
/// <remarks>
/// See http://entlib.codeplex.com/discussions/212973 and http://entlib.codeplex.com/discussions/211288
/// for a discussion of why this is necessary
/// </remarks>
public static class SqlDataReaderExtension
{
/// <summary>
/// Allows the internal <see cref="SqlDataReader"/> of a <see cref="RefCountingDataReader"/> to be accessed safely
/// </summary>
/// <remarks>
/// To ensure correct use, the returned reference must not be retained and used outside the scope of the input
/// reference. This is so that the reference counting does not get broken. In practice this means calling this method
/// on the base reader every time a reference to it is required.
/// </remarks>
public static SqlDataReader AsSqlDataReader(this RefCountingDataReader reader)
{
return (SqlDataReader)(reader.InnerReader);
}
/// <summary>
/// Allows the internal <see cref="SqlDataReader"/> of a <see cref="IDataReader"/> to be accessed safely
/// </summary>
/// <remarks>
/// To ensure correct use, the returned reference must not be retained and used outside the scope of the input
/// reference. This is so that the reference counting does not get broken. In practice this means calling this method
/// on the base reader every time a reference to it is required.
/// </remarks>
public static SqlDataReader AsSqlDataReader(this IDataReader reader)
{
return (SqlDataReader)(((RefCountingDataReader)(reader)).InnerReader);
}
}
... then to read data with an SQLReader, do something like this:
using (IDataReader reader = db.ExecuteReader(command))
{
while (reader.Read())
{
reader.GetInt32(reader.GetOrdinal("SomeColumn")),
reader.GetInt32(reader.GetOrdinal("SomeOtherColumn")),
reader.GetInt32(reader.GetOrdinal("SomeFurtherColumn")),
// Obtain the SQL data reader each time it is used
// (Note that GetDateTimeOffset is not on the standard IDataReader)
reader.AsSqlDataReader().GetDateTimeOffset(reader.GetOrdinal("SQLSpecificColumn"))
reader.AsSqlDataReader().GetDateTimeOffset(reader.GetOrdinal("AnotherSQLSpecificColumn"))
reader.GetString(reader.GetOrdinal("SomeAdditionalColumn"))
}
}
I think I have a working solution.
enter code here
' Create the Database object, using the default database service. The
' default database service is determined through configuration.
Dim db As Microsoft.Practices.EnterpriseLibrary.Data.Database = EnterpriseLibraryContainer.Current.GetInstance(Of Microsoft.Practices.EnterpriseLibrary.Data.Database)(DatabaseName)
Dim dbCommand As DbCommand
dbCommand = db.GetStoredProcCommand(StoredProcedureName)
'create a new database connection based on the enterprise library database connection
Dim dbConnection As System.Data.Common.DbConnection
dbConnection = db.CreateConnection
dbConnection.Open()
'set the dbCommand equal to the open dbConnection
dbCommand.Connection = dbConnection
'return a ADO sqlDatareader but still managed by the EnterpriseLibrary
Return dbCommand.ExecuteReader(CommandBehavior.CloseConnection)
You should use the interface, not the concrete class.
Public Function AssignedDepartmentDetail(ByVal Did As Integer) As IDataReader
Dim reader As IDataReader
Dim Command As SqlCommand = db.GetSqlStringCommand("select seomthing from somewhere where something = #did")
db.AddInParameter(Command, "#did", Data.DbType.Int32, Did)
reader = db.ExecuteReader(Command)
reader.Read()
Return reader
End Function
and the usage. Personally, I would never use a datareader in a presentation layer page, but to each his/her own I guess.
Private Const TemplateFileName_Select_Column_Ordinal As Integer = 0
Private Const Id_Select_Column_Ordinal As Integer = 1
Private Sub DoSomething()
dim reader as IDataReader
reader = includes.AssignedDepartmentDetail(Did)
If reader.HasRows Then
TheModule = reader(TemplateFileName_Select_Column_Ordinal)
PageID = reader(Id_Select_Column_Ordinal)
Else
TheModule = "#"
reader.Close() ''Dude, close your reader(s)
End If

JDEdwards XMLInterop

Wondering if anybody out there has any success in using the JDEdwards XMLInterop functionality. I've been using it for a while (with a simple PInvoke, will post code later). I'm looking to see if there's a better and/or more robust way.
Thanks.
As promised, here is the code for integrating with JDEdewards using XML. It's a webservice, but could be used as you see fit.
namespace YourNameSpace
{
/// <summary>
/// This webservice allows you to submit JDE XML CallObject requests via a c# webservice
/// </summary>
[WebService(Namespace = "http://WebSite.com/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class JdeBFService : System.Web.Services.WebService
{
private string _strServerName;
private UInt16 _intServerPort;
private Int16 _intServerTimeout;
public JdeBFService()
{
// Load JDE ServerName, Port, & Connection Timeout from the Web.config file.
_strServerName = ConfigurationManager.AppSettings["JdeServerName"];
_intServerPort = Convert.ToUInt16(ConfigurationManager.AppSettings["JdePort"], CultureInfo.InvariantCulture);
_intServerTimeout = Convert.ToInt16(ConfigurationManager.AppSettings["JdeTimeout"], CultureInfo.InvariantCulture);
}
/// <summary>
/// This webmethod allows you to submit an XML formatted jdeRequest document
/// that will call any Master Business Function referenced in the XML document
/// and return a response.
/// </summary>
/// <param name="Xml"> The jdeRequest XML document </param>
[WebMethod]
public XmlDocument JdeXmlRequest(XmlDocument xmlInput)
{
try
{
string outputXml = string.Empty;
outputXml = NativeMethods.JdeXmlRequest(xmlInput, _strServerName, _intServerPort, _intServerTimeout);
XmlDocument outputXmlDoc = new XmlDocument();
outputXmlDoc.LoadXml(outputXml);
return outputXmlDoc;
}
catch (Exception ex)
{
ErrorReporting.SendEmail(ex);
throw;
}
}
}
/// <summary>
/// This interop class uses pinvoke to call the JDE C++ dll. It only has one static function.
/// </summary>
/// <remarks>
/// This class calls the xmlinterop.dll which can be found in the B9/system/bin32 directory.
/// Copy the dll to the webservice project's /bin directory before running the project.
/// </remarks>
internal static class NativeMethods
{
[DllImport("xmlinterop.dll",
EntryPoint = "_jdeXMLRequest#20",
CharSet = CharSet.Auto,
ExactSpelling = false,
CallingConvention = CallingConvention.StdCall,
SetLastError = true)]
private static extern IntPtr jdeXMLRequest([MarshalAs(UnmanagedType.LPWStr)] StringBuilder server, UInt16 port, Int32 timeout, [MarshalAs(UnmanagedType.LPStr)] StringBuilder buf, Int32 length);
public static string JdeXmlRequest(XmlDocument xmlInput, string strServerName, UInt16 intPort, Int32 intTimeout)
{
StringBuilder sbServerName = new StringBuilder(strServerName);
StringBuilder sbXML = new StringBuilder();
XmlWriter xWriter = XmlWriter.Create(sbXML);
xmlInput.WriteTo(xWriter);
xWriter.Close();
string result = Marshal.PtrToStringAnsi(jdeXMLRequest(sbServerName, intPort, intTimeout, sbXML, sbXML.Length));
return result;
}
}
}
You have to send it messages like the following one:
<jdeRequest type='callmethod' user='USER' pwd='PWD' environment='ENV'>
<callMethod name='GetEffectiveAddress' app='JdeWebRequest' runOnError='no'>
<params>
<param name='mnAddressNumber'>10000</param>
</params>
</callMethod>
</jdeRequest>
To anyone trying to do this, there are some dependencies to xmlinterop.dll.
you'll find these files on the fat client here ->c:\E910\system\bin32
this will create a 'thin client'
PSThread.dll
icudt32.dll
icui18n.dll
icuuc.dll
jdel.dll
jdeunicode.dll
libeay32.dll
msvcp71.dll
ssleay32.dll
ustdio.dll
xmlinterop.dll
I changed our JDE web service to use XML Interop after seeing this code, and we haven't had any stability problems since. Previously we were using the COM Connector, which exhibited regular communication failures (possibly a connection pooling issue?) and was a pain to install and configure correctly.
We did have issues when we attempted to use transactions, but if you're doing simple single business function calls this shouldn't be an problem.
Update: To elaborate on the transaction issues - if you're attempting to keep a transaction alive over multiple calls, AND the JDE application server is handling a modest number of concurrent calls, the xmlinterop calls start returning an 'XML response failed' message and the DB transaction is left open with no way to commit or rollback. It's possible tweaking the number of kernels might solve this, but personally, I'd always try to complete the transaction in a single call.