Daki
Posts: 57
Joined: 16 Aug 2013, 00:48

Re: Build tool refusing Class directive

03 Sep 2013, 00:11

Thanks for your response - I forgot to make that call so I am pretty sure that is what the problem is.

I'm a little confused though on how to set up the dll so my game is aware of the NsRegisterReflection method. I would think I need to declare it in a header that my game includes but in all the Noesis code I see it is in a cpp file and the Noesis tools seem to pick it up without any issues. Again, I am new to creating dlls but the information I see online is suggesting I put that function in a header. I tried that but then the Noesis tools fail to load the xaml so I may be setting that up incorrectly. Is this process of generating a dll and then referencing it from within an application explained in more detail somewhere?

Also, as I am using Ogre to insert that call where it needs to go requires me to edit the Ogre Bindings. That really isn't a problem for me as I am including the source directly anyway but I figured I should call that out so that hooks can be built in for future releases of the bindings project.
 
User avatar
jsantos
Site Admin
Posts: 2905
Joined: 20 Jan 2012, 17:18
Contact:

Re: Build tool refusing Class directive

03 Sep 2013, 16:24

Yes, how to handle extensions to NoesisGUI are left to the user. In fact, our tools use a dynamic systems that scans all the DLLs found in a directory and registers them.

But that solution is quite generic and probably people don't need that complexlity. In fact, you probably have always a single DLL (or even not having a DLL) and the solution is as simple as calling the function to register all the elements.

You don't need to declare the function in the header to be exported. Having it in the cpp is enough to be recognized by XamlPlayer. But you probably will need a header to call it yourself from your application.
extern "C" NS_DLL_EXPORT void NsRegisterReflection(ComponentFactory* factory, NsBool registerComponents)
{
    NS_REGISTER_COMPONENT(UppercaseConverter)
}
I don't think this should affect the Ogre bidings. It is a custom code you can insert after Noesis initialization. You must invoke manually the function:
// Setup NsGui
Noesis_Init(mSceneMgr);

NsRegisterReflection(NsGetKernel()->GetComponentFactory(), true);

Noesis_LoadXAML(&mUIRoot, &mUIRenderer, "Gui/Samples/Time.xaml");
Noesis_RendererAntialiasingMode(mUIRenderer, 1); // PAA
Although bindings could be improved to have a callback that is invoked automatically and the user can fill with its registrations.
 
Daki
Posts: 57
Joined: 16 Aug 2013, 00:48

Re: Build tool refusing Class directive

04 Sep 2013, 04:23

Thanks again for your response. I've set up my extensions dll with a header so that I can reference it from my game. The Noesis resource builder parses it fine and generates the resources, but when I call
NsRegisterReflection(NsGetKernel()->GetComponentFactory(), true);
in my game I get the following exception from line 148 in ComponentFactoryImpl.cpp:

"Component 'Converter<Bool> (TypeConverter)' already registered"

It is very possible I have set up something incorrectly within my extensions dll. Here is the relevant code from within that project:

GuiExtensions.h (included by my game):
#include "stdafx.h"

#include <NsGui/UserControl.h>
#include <NsCore/TypeId.h>

extern "C" NS_DLL_EXPORT
void NsRegisterReflection(Noesis::Core::ComponentFactory* factory, NsBool registerComponents);
GuiExtensions.cpp
#include "stdafx.h"

#include <NsGui/UserControl.h>
#include <NsCore/TypeId.h>

#include "NumericUpDown.h"

extern "C" NS_DLL_EXPORT
void NsRegisterReflection(Noesis::Core::ComponentFactory* factory, NsBool registerComponents)
{
    NS_REGISTER_COMPONENT(NumericUpDown)
};
NumericUpDown.h
#include "stdafx.h"

#pragma warning(disable: 4275)
#pragma warning(disable: 4251)


#include <Noesis.h>
#include <NsGui/UserControl.h>
#include <NsGui/UIElementData.h>
#include <NsGui/FrameworkPropertyMetaData.h>
#include <NsGui/RoutedEvent.h>
#include <NsCore/ReflectionImplement.h>
#include <NsCore/TypeId.h>
#include <NsCore/Package.h>

using namespace Noesis;
using namespace Noesis::Core;
using namespace Noesis::Gui;

////////////////////////////////////////////////////////////////////////////////////////////////////
class NumericUpDown: public UserControl
{
public:
    /// Gets or sets numeric spinner value
    //@{
    NsInt32 GetValue() const;
    void SetValue(NsInt32 value);
    //@}

public:
    static const DependencyProperty* ValueProperty;
    static const RoutedEvent* ValueChangedEvent;

protected:
    virtual void OnValueChanged(const RoutedPropertyChangedEventArgs<NsInt32>& args);

    /// From DependencyObject
    //@{
    NsBool OnPropertyChanged(const Gui::DependencyPropertyChangedEventArgs& args);
    //@}

private:
    void UpButton_Click(BaseComponent* sender, const Gui::RoutedEventArgs& e);

    void DownButton_Click(BaseComponent* sender, const Gui::RoutedEventArgs& e);

	NS_IMPLEMENT_INLINE_REFLECTION(NumericUpDown, UserControl)
	{
		NsMeta<TypeId>("NumericUpDown");

		NsProp("Value", &NumericUpDown::GetValue, &NumericUpDown::SetValue);

		NsFunc("UpButton_Click", &NumericUpDown::UpButton_Click);
		NsFunc("DownButton_Click", &NumericUpDown::DownButton_Click);

		NsString source = "Gui/WKDX/numeric_up_down.xaml";

		Ptr<UIElementData> data = NsMeta<UIElementData>(TypeOf<SelfClass>());
		data->RegisterProperty<NsInt32>(ValueProperty, "Value",
			FrameworkPropertyMetadata::Create(NsInt32(0), FrameworkOptions_None));
		data->OverrideMetadata<NsString>(UserControl::SourceProperty, "Source",
			FrameworkPropertyMetadata::Create(source, FrameworkOptions_None));

		data->RegisterEvent(ValueChangedEvent, "ValueChanged", RoutingStrategy_Bubbling);
	}
};
NumericUpDown.cpp
#include "stdafx.h"

#pragma warning(disable: 4275)
#pragma warning(disable: 4251)

#include "NumericUpDown.h"

#include <Noesis.h>
#include <NsGui/UserControl.h>
#include <NsGui/UIElementData.h>
#include <NsGui/FrameworkPropertyMetaData.h>
#include <NsGui/RoutedEvent.h>
#include <NsCore/ReflectionImplement.h>
#include <NsCore/TypeId.h>
#include <NsCore/Package.h>


using namespace Noesis;
using namespace Noesis::Core;
using namespace Noesis::Gui;

const DependencyProperty* NumericUpDown::ValueProperty;
const RoutedEvent* NumericUpDown::ValueChangedEvent;

NsInt32 NumericUpDown::GetValue() const
{
    return DependencyObject::GetValue<NsInt32>(ValueProperty);
}

void NumericUpDown::SetValue(NsInt32 value)
{
    DependencyObject::SetValue<NsInt32>(ValueProperty, value);
}

void NumericUpDown::OnValueChanged(const RoutedPropertyChangedEventArgs<NsInt32>& args)
{
    RaiseEvent(args);
}

NsBool NumericUpDown::OnPropertyChanged(const Gui::DependencyPropertyChangedEventArgs& args)
{
    NsBool handled = ParentClass::OnPropertyChanged(args);

    if (!handled)
    {
        if (args.prop == ValueProperty)
        {
            NsInt32 oldValue = *static_cast<const NsInt32*>(args.oldValue);
            NsInt32 newValue = *static_cast<const NsInt32*>(args.newValue);

            RoutedPropertyChangedEventArgs<NsInt32> e(this, ValueChangedEvent,
                oldValue, newValue);
            OnValueChanged(e);

            return true;
        }
    }

    return handled;
}

void NumericUpDown::UpButton_Click(BaseComponent* sender, const Gui::RoutedEventArgs& e)
{
    SetValue(GetValue() + 1);
}

void NumericUpDown::DownButton_Click(BaseComponent* sender, const Gui::RoutedEventArgs& e)
{
    SetValue(GetValue() - 1);
}

//extern "C" NS_DLL_EXPORT
//void NsRegisterReflection(Noesis::Core::ComponentFactory* factory, NsBool registerComponents)
//{
//    NS_REGISTER_COMPONENT(NumericUpDown)
//};
Do you notice any errors with how I have this set up?

Thanks for you help.
 
User avatar
jsantos
Site Admin
Posts: 2905
Joined: 20 Jan 2012, 17:18
Contact:

Re: Build tool refusing Class directive

04 Sep 2013, 17:35

in my game I get the following exception from line 148 in ComponentFactoryImpl.cpp:

"Component 'Converter<Bool> (TypeConverter)' already registered"

It is very possible I have set up something incorrectly within my extensions dll. Here is the relevant code from within that project:
Hmm... I think I know what is happening here. There are two functions named NsRegisterReflection, one in Noesis.dll and the other one in your DLL. And being in the globalnamespace (because they have to be exported) the compiler is not able to distinguish them. When you are calling your NsRegisterReflection you are in fact calling the version found in Noesis.dll. And you are getting errors about component already registered because that function can only be invoked once.

We need to fix this by renaming the funcion NsRegisterReflection found in Noesis.dll. Meanwhile as a temporal fix, you have to duplicate your NsRegisterReflection function (give it another name) and call that one from your code.

I don't know if my explanation is clear. Hope so...
 
Daki
Posts: 57
Joined: 16 Aug 2013, 00:48

Re: Build tool refusing Class directive

05 Sep 2013, 01:05

Yep, that was the problem. The NumericUpDown example is loading fine now in my game so I am in a good spot to progress with my own controls. Thanks for your help!
 
User avatar
jsantos
Site Admin
Posts: 2905
Joined: 20 Jan 2012, 17:18
Contact:

Re: Build tool refusing Class directive

06 Sep 2013, 00:00

I think we don't have to change anything, the current architecture is correct.
  • You register your components in a new function called as you wish.
  • You implement the required exported function NsRegisterReflection. It is implemented by invoking the function defined above.

Who is online

Users browsing this forum: No registered users and 1 guest