NERvDN Library  0.2.0.20160420-0019
NERvLibrary - Nerve Gear Developer Network
Implementation of Components

This tutorial will show you how to use this SDK to implement components then register them to NERvGear.

The completed project is located in the samples\Data Source Demo folder.

Defining A Component Object

A component object is generally a C++ class implementing a number of interfaces. You will find that writing a component object is just as simple as writing a common inherited class.

// DemoDataSource.h
#include <NERvGear/interface/IDataSource.h>
#include <NERvGear/object.h>
class DemoDataSource : public NERvGear::IDataSource {
public:
virtual long NVG_METHOD GetId(NERvGear::UID* id);
virtual size_t NVG_METHOD GetName(size_t len, wchar_t* name);
virtual size_t NVG_METHOD GetDescrip(size_t len, wchar_t* descrip);
virtual unsigned NVG_METHOD GetDataCount();
virtual long NVG_METHOD GetData(unsigned index, NERvGear::IData** data);
virtual long NVG_METHOD FindData(const NERvGear::UID& id, NERvGear::IData** data);
DemoDataSource(); // Component object accepts default constructor only.
virtual ~DemoDataSource();
private:
NVG_DECLARE_OBJECT(DemoDataSource)
};

The codes above declare a class implementing the NERvGear::IDataSource interface. Specially, you should use the NVG_DECLARE_OBJECT() macro in the end of your class to accomplish the left essential codes for a component object.

Object Declaration

Like implementation of a plug-in, we should specify the information for the component object.

// DemoDataSource.cpp
#include "DemoDataSource.h"
#include <NERvGear/NERvSDK.h>
using namespace NERvGear;
NVG_BEGIN_OBJECT_INFO(DemoDataSource)
// Declare this object as a 'Data Source' component implementation.
NVG_DECLARE_OBJECT_CLASSID_UID(ID_CDataSource)
// The identity of this object.
// {E8295E65-DEAF-416E-B11D-003555297090}
NVG_DECLARE_OBJECT_OBJECTID(0xe8295e65, 0xdeaf, 0x416e, 0xb1, 0x1d, 0x0, 0x35, 0x55, 0x29, 0x70, 0x90)
NVG_DECLARE_OBJECT_VERSION(1, 0, 0)
NVG_DECLARE_OBJECT_NAME("Data Source")
NVG_DECLARE_OBJECT_DESCRIP("Demo Data Source Component")
NVG_END_OBJECT_INFO()

Interface Information

Each component object implements at least one interface, no exception, even the plug-in object. We have to indicate the interfaces that our object supported, and specially the plug-in declaration macro help us filling the default interface information, but you are still able to override it.

Here's the codes how we can declare the interface information for the component object, you can copy and paste the codes following the object information block:

NVG_BEGIN_INTERFACE_INFO(DemoDataSource)
NVG_DECLARE_INTERFACE(ID_IUnknown, IUnknown, this)
NVG_DECLARE_INTERFACE(ID_IDataSource, IDataSource, this)
NVG_END_INTERFACE_INFO()

This macro block actually implements the IUnknown::QueryInterface() method which is part of the COM standard. The IUnknown interface is very important and necessary to all the component objects, you should never forget to declare this interface for your objects.

Implementing The Interfaces

We're almost finished, except for the interface implementation. Just write the implementation codes for all the methods of each interface to accomplish this component object.

...
long DemoDataSource::GetId(NERvGear::UID* id)
{
if (id == NULL)
return E_INVALIDARG;
*id = STATIC_OBJECT_INFO.objectID;
return S_OK;
}
size_t DemoDataSource::GetName(size_t len, wchar_t* name)
{
return NERvCopyString(NVG_TEXT("Demo Data Collection"), len, name);
}
size_t DemoDataSource::GetDescrip(size_t len, wchar_t* descrip)
{
return NERvCopyString(NVG_TEXT("Data Source Component Sample"), len, descrip);
}
unsigned DemoDataSource::GetDataCount()
{
return DATA_COUNT;
}
long DemoDataSource::GetData(unsigned index, NERvGear::IData** data)
{
if (index >= DATA_COUNT || data == NULL)
return E_INVALIDARG;
switch (index) {
case DEMO_DATA_1: *data = nvg_new DemoData1(this); break;
case DEMO_DATA_2: *data = nvg_new DemoData2(this); break;
default: return E_FAIL;
}
return S_OK;
}
long DemoDataSource::FindData(const NERvGear::UID& id, NERvGear::IData** data)
{
if (data == NULL)
return E_INVALIDARG;
if (id == DemoData1::ID) {
*data = nvg_new DemoData1(this);
} else if (id == DemoData2::ID) {
*data = nvg_new DemoData2(this);
} else { return E_FAIL; }
return S_OK;
}
...

Notes that you can find the interface details and implementing instruction in each interface header, please read them carefully and follow the documents strictly.

Object Registration

Finally we have done our implementation of a Data Source component, we should tell NERvGear that there's a new available object for this component.

// DataSourceDemo.cpp
...
NVG_BEGIN_COMPONENT_REGISTER(DataSourceDemo)
NVG_REGISTER_OBJECT(DemoDataSource, false) // no aggregation
NVG_END_COMPONENT_REGISTER()
...

Just as what the previous tutorial referred in the "Components Registration" section, we can declare the demo Data Source component object in the component registration macro block.

Testing The Data Source Object

After compiling your plug-in, you would better test it before launching to users. Copy your compiled DLL to the bin\win(32/64)\Plugins\YOUR PLUG-IN FOLDER then run NERvGear.exe.

Data Picker

When you click the Ready button in the frame of NERvSDK Plug-in Manager, your plug-in DLL will be loaded into NERvGear and the objects will be registered automatically. Click the Show Data Picker... button and find your Data Source object to test all of its functions.