I have a multiplatform kotlin project generating a shared library for mingwx64. Once I have generated the DLL, I have incorporated it into a C++ project and now i need to call a function that takes the implementation of an interface as a parameter, but I have no idea how to get it.
I attach example code to explain it:
//Kotlin Multiplatform code
interface InitializationEvents {
fun onComplete()
fun onError(error: String)
}
class MyClass {
fun initialize(succeed: Boolean, listener: InitializationEvents) {
if(succeed)
listener.onComplete()
else
listener.onError("Error description")
}
}
It generates a header file like this:
//libnative.h
typedef {
...
/* User functions. */
struct {
struct {
struct {
libnative_KType* (*_type)(void);
void (*onComplete)(libnative_kref_InitializationEvents thiz);
void (*onError)(libnative_kref_InitializationEvents thiz, const char* error);
} InitializationEvents;
struct {
libnative_KType* (*_type)(void);
libnative_kref_MyClass (*MyClass)();
void (*initialize)(libnative_kref_MyClass thiz, libnative_KBoolean succeed, libnative_kref_InitializationEvents listener);
} MyClass;
} root;
} kotlin;
} libnative_ExportedSymbols;
extern libnative_ExportedSymbols* libnative_symbols(void);
And now I'm using this Cpp code:
// Demo.cpp
int main()
{
libnative_ExportedSymbols* lib = libnative_symbols();
libnative_kref_MyClass myClass = lib->kotlin.root.MyClass.MyClass();
//I guess I have to do something here... 😅
libnative_kref_InitializationEvents listener = { .pinned = NULL };
lib->kotlin.root.MyClass.initialize(myClass, true, listener);
}
void myOnComplete() { }
void myOnError(const char* error) { }
It would need to be able to receive the call to the myOnComplete and myOnError functions as desired by the library.
Thank you very much.
Related
I have a dynamic linked library in C++. What I want to do is have a callback function declared in the library and leave it to the user to define in their code that uses the library. Pseudo-code example:
//in library
void userDefinedFunction();
void libraryFunction() {
//do stuff
userDefinedFunction();
//do more stuff
}
//in user code
void userDefinedFunction() {
//user-specific code
}
Is this possible in modern C++?
Of course. Your library could accept a function pointer to a user defined function or a reference to a functor given by the user. The void libraryFunction() will just use that to call the user function.
You can use std::function from functional library. Here is an example with lambda expression and function
#include <iostream>
#include <functional>
std::function<int (int)> func;
int testfunc(int i)
{
std::cout<<"testfunc function called ";
return i+7;
}
void process()
{
if (func)
std::cout<<func(3)<<std::endl;
}
int main()
{
process();
func = [](int i) {
std::cout<<"Lambda function called ";
return i+4;
};
process();
func = testfunc;
process();
return 0;
}
I'm currently developing a nodejs module, written in C++ and I've been looking for a way to convert a v8::Object to a cv::Mat object from opencv, without any luck for now.
I saw that nan library could help to convert objects, but i couldn't find how, I don't even know if it's possible to convert them in my case.
The v8 juice project would meet my expectations but since it has been abandoned, I just don't know how to do this.
Here is a snippet of what I'm trying to do :
void
BRMatcher::run(const v8::FunctionCallbackInfo<v8::Value>& args)
{
v8::Isolate* isolate = v8::Isolate::GetCurrent();
v8::HandleScope scope(isolate);
if (args.Length() < 1)
{
isolate->ThrowException(v8::Exception::TypeError(v8::String::NewFromUtf8(isolate, "Missing parameter [Mat img].")));
return ;
}
if (!args[0]->IsObject())
{
isolate->ThrowException(v8::Exception::TypeError(v8::String::NewFromUtf8(isolate, "Parameter [Mat img] must be an object.")));
return ;
}
v8::Local<v8::Object> cvMat(args[0]->ToObject());
Mat img = ??? // This is where I ended up...
// ...
}
All the posts talking about this on StackOverflow are outdated (older versions or tools that are not working anymore...)
So my questions are: how can I convert the argument I receive in my function to a cv::Mat object ? To any type I want ?
Any help would be appreciated, thanks!
At first I would recommend to look on existing openCV bindings for Node.js like node-opencv.
If you need to bind C++ and JavaScript code, there are several libraries. As an author of one of them, v8pp, I know about several other:
vu8 (abandoned)
v8-juice (abandoned)
Script bindng in cpgf
Embind
As I know, to convert a C++ object into v8::Object all of them use v8::Object::SetAlignedPointerInInternalField() function.
C++ object to v8::Object conversions are usually performed with mapping of a C++ pointer to persistent handle of the V8 object in a map container.
Do have a look on the Nodejs.org C++ addon and Nan tutorials. Though both are a little misleading, they anyhow describe the canonical way. Use Nan over direct V8 APIs since especially this part (was and still) is changing a lot.
With Nan what you're looking for is passing wrapped objects. More precisely this line is the heart of it.
In this fork of Node-OpenCV, I am doing exactly that with cv::Mat in order to make it a first class object for JS-land. Maybe this implementation may help you.
TL;DR
Wrap the object with Nan::ObjectWrap and pass it around. Internally uses v8::SetInternalFieldPointer(); for you. This is basically copy-paste-able.
// lib/mat.js
var cv = require('./bindings')('addon');
function Mat() {
}
/**
* returns the wrapped c++ object
* [arguments optional]
*/
Mat.prototype.createMat = function (a) {
var args = Array.prototype.slice.call(arguments);
return cv.Mat.createMat(args[0])
}
// src/addon.cc
// just initializes all your modules. Magic happening in mat.h and matwrap.h
// matwrap.cc is the implementation of the wrapped object. mat.cc holds
// JS-libarary specific methods
#include <nan.h>
#include "opencv.h"
#include "imgproc.h"
#include "mat.h"
#include "matwrap.h"
void InitAll(v8::Local<v8::Object> exports) {
Opencv::Init(exports);
ImgProc::Init(exports);
Matwrap::Init();
Mat::Init(exports);
}
NODE_MODULE(addon, InitAll)
Important stuff here...
// src/matwrap.h
#ifndef MATWRAP_H
#define MATWRAP_H
#include <opencv2/opencv.hpp>
#include <nan.h>
class Matwrap : public Nan::ObjectWrap {
public:
static void Init();
static v8::Local<v8::Object> NewInstance(v8::Local<v8::Value> arg);
cv::Mat Val() const { return val_; }
private:
Matwrap();
~Matwrap();
static Nan::Persistent<v8::Function> constructor;
static void New(const Nan::FunctionCallbackInfo<v8::Value>& info);
cv::Mat val_;
};
#endif
...and here you're are wrapping it (basically that's it; follow below for consumption):
// src/matwrap.cc
#include <node.h>
#include "matwrap.h"
#include <opencv2/opencv.hpp>
Matwrap::Matwrap() {};
Matwrap::~Matwrap() {};
Nan::Persistent<v8::Function> Matwrap::constructor;
void Matwrap::Init() {
Nan::HandleScope scope;
// Prepare constructor template
v8::Local<v8::FunctionTemplate> tpl = Nan::New<v8::FunctionTemplate>(New);
tpl->SetClassName(Nan::New("Matwrap").ToLocalChecked());
tpl->InstanceTemplate()->SetInternalFieldCount(1);
constructor.Reset(tpl->GetFunction());
}
void Matwrap::New(const Nan::FunctionCallbackInfo<v8::Value>& info) {
// wrap it...
Matwrap* obj = new Matwrap();
cv::Mat src;
obj->val_ = src;
obj->Wrap(info.This());
// return wrapped here...
info.GetReturnValue().Set(info.This());
}
v8::Local<v8::Object> Matwrap::NewInstance(v8::Local<v8::Value> arg) {
Nan::EscapableHandleScope scope;
// const unsigned argc = 1;
// v8::Local<v8::Value> argv[argc] = { arg };
v8::Local<v8::Function> cons = Nan::New<v8::Function>(constructor);
v8::Local<v8::Object> instance = cons->NewInstance();
return scope.Escape(instance);
}
For consumption you could do stuff like this:
// lib/mat.js
/**
* Returns true if the array has no elements.
* #param {Object} mat - native cv::Mat
* #return {Boolean}
*/
Mat.prototype.empty = function (mat) {
var args = Array.prototype.slice.call(arguments);
return cv.Mat.empty(args[0])
}
// src/mat.h
// This is your API
#ifndef MAT_H
#define MAT_H
// #include <opencv2/opencv.hpp>
#include <nan.h>
class Mat : public Nan::ObjectWrap {
public:
static void Init(v8::Local<v8::Object> exports);
private:
explicit Mat(double value = 0);
~Mat();
static void New(const Nan::FunctionCallbackInfo<v8::Value>& info);
static void CreateMat(const Nan::FunctionCallbackInfo<v8::Value>& info);
static void Empty(const Nan::FunctionCallbackInfo<v8::Value>& info);
static void Total(const Nan::FunctionCallbackInfo<v8::Value>& info);
static void Type(const Nan::FunctionCallbackInfo<v8::Value>& info);
static Nan::Persistent<v8::Function> constructor;
double value_;
};
#endif
// src/mat.cc
#include "mat.h"
#include "matwrap.h"
#include <opencv2/opencv.hpp>
Nan::Persistent<v8::Function> Mat::constructor;
Mat::Mat(double value) : value_(value) {
}
Mat::~Mat() {
}
void Mat::Init(v8::Local<v8::Object> exports) {
Nan::HandleScope scope;
// Prepare constructor template
v8::Local<v8::FunctionTemplate> tpl = Nan::New<v8::FunctionTemplate>(New);
tpl->SetClassName(Nan::New("Mat").ToLocalChecked());
tpl->InstanceTemplate()->SetInternalFieldCount(1);
// Prototype
Nan::SetPrototypeMethod(tpl, "createMat", CreateMat);
Nan::SetPrototypeMethod(tpl, "empty", Empty);
Nan::SetPrototypeMethod(tpl, "total", Total);
Nan::SetPrototypeMethod(tpl, "type", Type);
constructor.Reset(tpl->GetFunction());
exports->Set(Nan::New("Mat").ToLocalChecked(), tpl->GetFunction());
}
void Mat::New(const Nan::FunctionCallbackInfo<v8::Value>& info) {
if (info.IsConstructCall()) {
// Invoked as constructor: `new Opencv(...)`
double value = info[0]->IsUndefined() ? 0 : info[0]->NumberValue();
Mat* obj = new Mat(value);
obj->Wrap(info.This());
info.GetReturnValue().Set(info.This());
} else {
// Invoked as plain function `Opencv(...)`, turn into construct call.
const int argc = 1;
v8::Local<v8::Value> argv[argc] = { info[0] };
v8::Local<v8::Function> cons = Nan::New<v8::Function>(constructor);
info.GetReturnValue().Set(cons->NewInstance(argc, argv));
}
}
void Mat::CreateMat(const Nan::FunctionCallbackInfo<v8::Value>& info) {
info.GetReturnValue().Set(Matwrap::NewInstance(info[0]));
}
void Mat::Empty(const Nan::FunctionCallbackInfo<v8::Value>& info) {
Matwrap* obj = Nan::ObjectWrap::Unwrap<Matwrap>(info[0]->ToObject());
// check through cv::Mat::empty()
if (obj->Val().empty()) {
// return JS bool
info.GetReturnValue().Set(Nan::True());
} else {
// TODO: logically not correct
info.GetReturnValue().Set(Nan::False());
}
}
I've got problems passing a member function of a C++ CLI class to a native C callback from a library.
To be precise its the Teamspeak 3 SDK.
You can pass a non member function using the following code without problem:
struct ClientUIFunctions funcs;
/* Initialize all callbacks with NULL */
memset(&funcs, 0, sizeof(struct ClientUIFunctions));
funcs.onConnectStatusChangeEvent = onConnectStatusChangeEvent;
But I need to pass a pointer to a member function, for example:
funcs.onConnectStatusChangeEvent = &MyClass::onConnectStatusChangeEvent;
Any other idea how to use the event within a non static member function is welcome to.
Thanks in advance!
This can only be done via a static class function because C doesn't know anything about the vtable or what object the function is part of. See below for a C++ and Managed C++ example
This could however be a work around, build a wrapper class which handles all the callbacks you need.
#include <string.h>
struct ClientUIFunctions
{
void (*onConnectStatusChangeEvent)(void);
};
class CCallback
{
public:
CCallback()
{
struct ClientUIFunctions funcs;
// register callbacks
my_instance = this;
/* Initialize all callbacks with NULL */
memset(&funcs, 0, sizeof(struct ClientUIFunctions));
funcs.onConnectStatusChangeEvent = sOnConnectStatusChangeEvent;
}
~CCallback()
{
// unregister callbacks
my_instance = NULL;
}
static void sOnConnectStatusChangeEvent(void)
{
if (my_instance)
my_instance->OnConnectStatusChangeEvent();
}
private:
static CCallback *my_instance;
void OnConnectStatusChangeEvent(void)
{
// real callback handler in the object
}
};
CCallback *CCallback::my_instance = NULL;
int main(int argc, char **argv)
{
CCallback *obj = new CCallback();
while (1)
{
// do other stuff
}
return 0;
}
Another possibility would be if the callback supports and void *args like void (*onConnectStatusChangeEvent)(void *args); which you can set from the plugin. You could set the object in this args space so in de sOnConnectStatusChangeEvent you would have something like this:
static void sOnConnectStatusChangeEvent(void *args)
{
if (args)
args->OnConnectStatusChangeEvent();
}
For managed C++ it should be something like this, however I can't get it to compile because it doesn't like the template brackets..
wrapper.h:
using namespace std;
using namespace System;
using namespace System::Runtime::InteropServices;
using namespace System::Text;
namespace Test
{
struct ClientUIFunctions
{
void (*onConnectStatusChangeEvent)(void);
};
public delegate void ConnectStatusChangeEvent(void);
public ref class ManagedObject
{
public:
// constructors
ManagedObject();
// destructor
~ManagedObject();
//finalizer
!ManagedObject();
event ConnectStatusChangeEvent^ OnConnectStatusChangeEvent {
void add(ConnectStatusChangeEvent^ callback) {
m_connectStatusChanged = static_cast<ConnectStatusChangeEvent^> (Delegate::Combine(m_connectStatusChanged, callback));
}
void remove(ConnectStatusChangeEvent^ callback) {
m_connectStatusChanged = static_cast<ConnectStatusChangeEvent^> (Delegate::Remove(m_connectStatusChanged, callback));
}
void raise(void) {
if (m_connectStatusChanged != nullptr) {
m_connectStatusChanged->Invoke();
}
}
}
private:
ConnectStatusChangeEvent^ m_connectStatusChanged;
};
class CCallback
{
public:
static void Initialize(ManagedObject^ obj);
static void DeInitialize(void);
private:
static void sOnConnectStatusChangeEvent(void);
static gcroot<ManagedObject^> m_objManagedObject;
};
}
wrapper.cpp:
#include <string.h>
#include "wrapper.h"
using namespace System;
using namespace Test;
void CCallback::Initialize(ManagedObject^ obj)
{
struct ClientUIFunctions funcs;
// register callbacks
m_objManagedObject = obj;
/* Initialize all callbacks with NULL */
memset(&funcs, 0, sizeof(struct ClientUIFunctions));
funcs.onConnectStatusChangeEvent = sOnConnectStatusChangeEvent;
}
void CCallback::DeInitialize(void)
{
// unregister callbacks
m_objManagedObject = nullptr;
}
void CCallback::sOnConnectStatusChangeEvent(void)
{
if (m_objManagedObject != nullptr)
m_objManagedObject->OnConnectStatusChangeEvent();
}
// constructors
ManagedObject::ManagedObject()
{
// you can't place the constructor in the header but just for the idea..
// create wrapper
CCallback::Initialize(this);
}
// destructor
ManagedObject::~ManagedObject()
{
this->!ManagedObject();
}
//finalizer
ManagedObject::!ManagedObject()
{
CCallback::DeInitialize();
}
gcroot<ManagedObject^> CCallback::m_objManagedObject = nullptr;
int main(array<System::String ^> ^args)
{
ManagedObject^ bla = gcnew ManagedObject();
while (1)
{
// do stuff
}
return 0;
}
I cant understand why in the class constructor I can call this function but when called in the test function, it errors out with
E:\Projects\NasuTek-Plugin-Engine\tests\CheckAddonEngine.cpp:64: error: conversion from 'std::auto_ptr<FakeSettableFeaturePlugin>' to 'std::auto_ptr<FakeFeature>' is ambiguous
C++ File
#include <ObjectEngine.h>
#include <memory>
#define BOOST_TEST_MAIN
#include <boost/test/unit_test.hpp>
class FakeFeature : public PObject {
public:
inline virtual const char *returnSomthingCool() { return "Somthing Cool"; }
};
class FakeFeaturePlugin : public FakeFeature {
public:
inline const char *returnSomthingCool() { return "Somthing Cool From a Plugin Object"; }
inline std::string getName() { return "Fake Feature Plugin Object"; }
};
class FakeSettableFeaturePlugin : public FakeFeature {
public:
inline const char *returnSomthingCool() { return _value; }
inline char *setSomthingCool(const char *value) { _value = const_cast<char *>(value); }
inline std::string getName() { return "Fake Feature Settable Plugin Object"; }
private:
char *_value;
};
typedef ObjectEngine<FakeFeature> FakeFeatureEngine;
class FakeApplication {
public:
inline FakeApplication(){
_engine = new FakeFeatureEngine();
std::auto_ptr<FakeFeature> pluginToAdd (new FakeFeaturePlugin);
_engine->addObject(pluginToAdd); // Essencially what im doing where it errors, both classes inherit FakeFeature
}
inline ~FakeApplication() {
delete _engine;
}
FakeFeatureEngine *_engine;
};
BOOST_AUTO_TEST_CASE(getengineobject) {
FakeApplication *application = new FakeApplication();
FakeFeature &feature = application->_engine->getObject("Fake Feature Plugin Object");
BOOST_CHECK_EQUAL(feature.getName(), "Fake Feature Plugin Object");
BOOST_CHECK_EQUAL(feature.returnSomthingCool(), "Somthing Cool From a Plugin Object");
delete application;
}
BOOST_AUTO_TEST_CASE(addobjecttoengine) {
FakeApplication *application = new FakeApplication();
std::auto_ptr<FakeSettableFeaturePlugin> plugin (new FakeSettableFeaturePlugin);
plugin.get()->setSomthingCool("Bro I Set this to this value ^_^");
application->_engine->addObject(plugin); // This is the line that fails
FakeFeature &feature = application->_engine->getObject("Fake Feature Settable Plugin Object");
BOOST_CHECK_EQUAL(feature.getName(), "Fake Feature Settable Plugin Object");
BOOST_CHECK_EQUAL(feature.returnSomthingCool(), "Bro I Set this to this value ^_^");
delete application;
}
.h File
/**
#file ObjectEngine.h
#brief Header File with Plugin Engine Templates to make adding a plugin interface to your app easier
*/
#ifndef NASUTEKPLUGINENGINE_H
#define NASUTEKPLUGINENGINE_H
#include <boost/ptr_container/ptr_list.hpp>
#include <boost/type_traits/is_base_of.hpp>
#include <stdio.h>
#include <string>
class PObject {
public:
inline PObject() {}
virtual std::string getName() = 0;
};
template<typename TObjectType>
class ObjectEngine {
public:
ObjectEngine() {}
~ObjectEngine() {
_objects.clear();
}
void addObject(std::auto_ptr<TObjectType> obj) {
if(boost::is_base_of<PObject, TObjectType>::value) {
_objects.push_back(obj.release());
}
}
TObjectType &getObject(std::string objectName) {
typename boost::ptr_list<TObjectType>::iterator i;
for(i = _objects.begin(); i != _objects.end(); i++) {
if((*i).getName() == objectName) {
return *i;
}
}
throw "Object does not exist.";
}
bool objectExist(std::string objectName) {
typename boost::ptr_list<TObjectType *>::iterator i;
for(i = _objects.begin(); i != _objects.end(); i++) {
if((*i).getName() == objectName) {
return true;
}
}
return false;
}
private:
boost::ptr_list<TObjectType> _objects;
};
#endif // NASUTEKPLUGINENGINE_H
What I'm trying to do is create a plugin engine for my projects while making it reusable, and the C++ file is making sure its working right.
This doesn't look like a problem with Boost Test, per se, but it looks like the line in addobjecttoengine...
std::auto_ptr<FakeSettableFeaturePlugin> plugin (new FakeSettableFeaturePlugin);
...should be...
std::auto_ptr<FakeFeature> plugin(new FakeSettableFeaturePlugin);
...the same as in FakeApplication's constructor. Then there's no conversion to perform at CheckAddonEngine.cpp:64.
I was trying to compile a simple Helloworld program for BADA but through command prompt.After compiling i ma getting the errors as
c:/Helloworld/src/Helloworld.cpp:12: error: prototype for 'Osp::App::Application HelloWorld::CreateInstance()' does not match any in class 'HelloWorld'
C:/Helloworld/inc/HelloWorld.h:21: error: candidate is: static Osp::App::Application* HelloWorld::CreateInstance()
could any body help that what needs to be done with it.
Thanks
Code for Helloworld.h
#ifndef __HELLOWORLD_H__
#define __HELLOWORLD_H__
#include <FBase.h>
#include <FGraphics.h>
#include <FLocales.h>
#include <FSystem.h>
#include <FApp.h>
using namespace Osp::Base;
using namespace Osp::Graphics;
using namespace Osp::Locales;
using namespace Osp::System;
using namespace Osp::App;
class HelloWorld :
public Application // must inherit from Application class
{
public:
// The application must have a factory method that creates an instance of the application.
static Application* CreateInstance(void);
public:
HelloWorld();
~HelloWorld();
public:
// The application must provide its name.
String GetAppName(void) const;
protected:
// The application must provide its ID.
AppId GetAppId(void) const;
AppSecret GetAppSecret(void) const;
public:
// This method is called when the application is initializing.
bool OnAppInitializing(AppRegistry& appRegistry);
// This method is called when the application is terminating.
bool OnAppTerminating(AppRegistry& appRegistry);
// Thie method is called when the application is brought to the foreground
void OnForeground(void);
// This method is called when the application is sent to the background.
void OnBackground(void);
// This method is called when the application has little available memory.
void OnLowMemory(void);
// This method is called when the device's battery level changes.
void OnBatteryLevelChanged(BatteryLevel batteryLevel);
};
#endif
Code for Helloworld.cpp
#include "HelloWorld.h"
HelloWorld::HelloWorld()
{
}
HelloWorld::~HelloWorld()
{
}
Application*
HelloWorld::CreateInstance(void)
{
// You can create the instance through another constructor.
return new HelloWorld();
}
String
HelloWorld::GetAppName(void) const
{
static String appName(L"HelloWorld");
return appName;
}
AppId
HelloWorld::GetAppId(void) const
{
static AppId appId(L"93bt1p123e");
return appId;
}
AppSecret
HelloWorld::GetAppSecret(void) const
{
static AppSecret appSecret(L"9C645DDBA19C71BAD1204DA4DAA7A0B9");
return appSecret;
}
bool
HelloWorld::OnAppInitializing(AppRegistry& appRegistry)
{
// TODO:
// Initialization including UI construction can be done here.
// Load the application's latest data, if necessary.
// If this method is successful, return true; otherwise, return false.
return true;
}
bool
HelloWorld::OnAppTerminating(AppRegistry& appRegistry)
{
// TODO:
// Deallocate or close any resources still alive.
// Save the application's current states, if applicable.
// If this method is successful, return true; otherwise, return false.
return true;
}
void
HelloWorld::OnForeground(void)
{
result r = E_SUCCESS;
Canvas* pCanvas = GetAppFrame()->GetCanvasN();
if(pCanvas == null)
return;
Font* pFont = new Font();
pFont->Construct(FONT_STYLE_PLAIN | FONT_STYLE_BOLD, 50);
pCanvas->SetFont(*pFont);
r = pCanvas->DrawText(Point(30, 30), GetAppName());
if (IsFailed(r))
{
AppLog("pCanvas->DrawText() failed.\n");
delete pCanvas;
return;
}
r = pCanvas->Show();
if (IsFailed(r))
{ AppLog("pCanvas->Show() failed.\n");
delete pCanvas;
return;
}
delete pCanvas;
}
void
HelloWorld::OnBackground(void)
{
}
void
HelloWorld::OnLowMemory(void)
{
// TODO:
// Deallocate as many resources as possible.
}
void
HelloWorld::OnBatteryLevelChanged(BatteryLevel batteryLevel)
{
// TODO:
// It is recommended that the application save its data,
// and terminate itself if the application consumes much battery
}
Code for Helloworldentry.cpp
/**
* OSP Application entry point(OspMain) introduced.
*/
#include <fapp.h>
#include "HelloWorld.h"
using namespace Osp::Base::Collection;
extern "C"
{
__declspec(dllexport) void OspMain(int hInstance, int argc, char *argv[]);
}
/**
* Entry function of OSP Application which is called by the operating system.
*/
extern "C" {
void OspMain(int hInstance, int argc, char *argv[])
{
AppLog("OspMain() Started. \n");
result r = E_SUCCESS;
ArrayList* pArgs = new ArrayList();
pArgs->Construct();
for (int i = 0; i < argc; i++)
{
String* pEachArg = new String(argv[i]);
pArgs->Add(*pEachArg);
}
r = Osp::App::Application::Execute(HelloWorld::CreateInstance, pArgs);
if (IsFailed(r))
{
AppLog("Application execution has failed.\n");
}
if (pArgs)
{
pArgs->RemoveAll(true);
delete pArgs;
}
AppLog("OspMain() Ended. \n");
}
}
The compiler is complaining that you have defined a method with this signature:
Osp::App::Application HelloWorld::CreateInstance()
whereas the HelloWorld class declares that its CreateInstance method has this signature:
Osp::App::Application* HelloWorld::CreateInstance()
Note the difference in the return type. The class definition says that the method with this name returns an Application pointer but you have implemented a method that returns an Application object.
In the future, please post code along with compiler errors. It's rarely possible to adequately explain compiler errors in isolation from the code that produced them. For example, I can't tell you which return type is correct in this case; I can only tell you that the return types don't match (which is exactly what the compiler already said).