How to activate an instance of a ref class - c++

Say I have this class:
public ref class Page1 sealed : Windows::UI::Xaml::Controls::Page {};
I can activate an instance of this class like this:
auto page = ref new Page1();
But how would I do that in raw C++?
I have tried this but it doesn't work:
Microsoft::WRL::Wrappers::HString className;
className.Set(L"App1.Page1");
IInspectable *page;
Windows::Foundation::ActivateInstance(className.Get(), &page);
The above code does work when I specify a windows runtime class name, (such as "Windows.UI.Xaml.Controls.Button"), just not my own ref class "App1.Page1".
Alternatively, given that I have declared a public ref class named Page1 in the App1 namespace, how can I activate an instance of this class as an IInspectable* from the HSTRING "App1.Page1"?

I think I have figured it out. Well, this answer does not directly solve the problem of activating any arbitrary type, but it does what I want.
The devil is in the detail. The XAML compiler will generate a bunch of files not visible in the Solution Explorer. These files have the extension .g.h and .g.hpp. You can click the "Show All Files" button in Solution Explorer to see them.
In App.g.h, the App class implements the Windows::UI::Xaml::Markup::IXamlMetadataProvider class, which we can use to obtain information about our XAML types. The XamlTypeInfo files contains the generated type definitions.
Here's some code which shows how to activate one of our XAML types from a TypeName:
Object^ activate(TypeName typeName)
{
auto app = Application::Current;
auto provider = static_cast<IXamlMetadataProvider^>(app);
auto xamlType = provider->GetXamlType(typeName);
return xamlType->ActivateInstance();
}
No WRL necessary, 100% C++/CX, thanks to the XAML type information generated by the XAML compiler!
I believe a similar structure is also the case for C# projects, in that the Application-derived class will implement IXamlMetadataProvider interface too. Under the hood, the Windows Runtime does not use .NET, so it does not have any kind of "real" reflection, so it relies on statically defined type definitions.

Related

A descendant of TStyledPresentationProxy has not been registered for class

I have a custom grid control that inherits from TGrid called TFmGrid. This control was working fine in Rad Studio 10 Seattle Update One. I recently upgraded to 10.1 Berlin and started noticing this error message showing up on my TFmGrid controls both when I run the application and in the designer:
A descendant of TStyledPresentationProxy has not been registered for class TFmGrid. Maybe it is necessary to add the FMX.Grid.Style module to the uses section
The image below shows how the error message shows up on my grid controls:
I started by doing as the message suggests, and adding #include <FMX.Grid.Style.hpp> to the header file of my TFmGrid control, however this seems to have done nothing.
So as far as trying to register a decendant of TStyledPresentationProxy I am not exactly sure where to start. I found this documentation about a method which:
Attempts to register the presentation proxy class with the specified name or the specified combination of control class and control type.
So I assume I need to use this method or at least something similar, but I don't understand how I am supposed to go about calling this method.
But then that brings up the question of WHERE do I call this code?
My custom control has a method in its namespace called Register() which I believe was autogenerated by the IDE when the control was created:
namespace Fmgridu
{
void __fastcall PACKAGE Register()
{
TComponentClass classes[1] = {__classid(TFmGrid)};
RegisterComponents(L"Kalos FM Controls", classes, 0);
}
}
Do I need to call something in there to register a decendant of TStyledPresentationProxy? What is the proper way to go about this?
Just override virtual method DefinePresentationName in you TfmGrid and return name of presentation name for grid:
function TfmGrid.DefinePresentationName: string;
begin
Result := 'Grid-' + GetPresentationSuffix;
end;
Fm registers presentation by string name and uses class name for it, so if you create new component (based on existed) you automatically change classname, so system cannot find presentation for you. There are two solution:
Said that you will use presentation from TGrid (DefinePresentationName)
Register existed presentation for you class (look at the initialization section of FMX.Grid.Style.pas)
P.S. Year ago i wrote article about it in common eNew approach of development of FireMonkey control “Control – Model – Presentation”. Part 1 I hope it will help you
It's simple :
Just put "StyleBook" component to your form
I had the same issue with a test component I was developing.
Complementing Yaroslav Brovin's speech, I solved the problem by adding the class register in the initialization and finalization clauses at the end of the unit, like this:
initialization
TPresentationProxyFactory.Current.Register(<COMPONENT CLASSNAME HERE>, TControlType.Styled, TStyledPresentationProxy<TStyledGrid>);
finalization
TPresentationProxyFactory.Current.Unregister(<COMPONENT CLASSNAME HERE>, TControlType.Styled, TStyledPresentationProxy<TStyledGrid>);
In my case looks like this:
initialization
TPresentationProxyFactory.Current.Register(TSGrid, TControlType.Styled, TStyledPresentationProxy<TStyledGrid>);
finalization
TPresentationProxyFactory.Current.Unregister(TSGrid, TControlType.Styled, TStyledPresentationProxy<TStyledGrid>);
PS: Don't forget to declare the FMX.Presentation.Factory,
FMX.Presentation.Style and FMX.Grid.Style units in the uses clause

How do I create a custom Layout for log4cplus

After searching for what feels far too long, I decided to ask this simple question on stackoverflow:
How do I create a custom Layout for log4cplus (1.1.2)?
The closest related question is How do I add a custom filter in log4cplus? where the author adds the new class directly into the log4cplus directory (or uses log4cplus namespace?). I do not have this option as the log4plus headers and libraries are installed independently (and simply setting the namespace to log4cplus does not work either.
What I tried is a minimal example inheriting from log4cplus::PatternLayout:
namespace myNameSpace {
class LOG4CPLUS_EXPORT MyPatternLayout: public ::log4cplus::PatternLayout {
public:
MyPatternLayout(const log4cplus::tstring& pattern);
MyPatternLayout(const log4cplus::helpers::Properties& properties);
~MyPatternLayout();
private:
// Disallow copying of instances of this class
MyPatternLayout(const MyPatternLayout&);
MyPatternLayout& operator=(const MyPatternLayout&);
};
}
I expect that LOG4CPLUS_EXPORT takes care of registering my class to the log4cplus framework so I can use it in the configuration file. However, adding
log4cplus.appender.STDOUT.layout=myNameSpace::MyPatternLayout
results in an error:
log4cplus:ERROR Cannot find LayoutFactory: "myNameSpace::MyPatternLayout"
So how do I register a custom Layout/Appender?
After trying many things, it boils down to one simple entry that has to be put after log4cplus::initialize(); and before log4cplus::PropertyConfigurator::doConfigure("<path to config file");.
If you want to add the new Layout in the log4cplus namespace you can simply
//example1
log4cplus::initialize();
// register our stuff
log4cplus::spi::LayoutFactoryRegistry& reg = log4cplus::spi::getLayoutFactoryRegistry();
LOG4CPLUS_REG_LAYOUT(reg, MyPatternLayout);
log4cplus::PropertyConfigurator::doConfigure(Logger::mConfigFile);
or, if you want to use your own namespace
//example2
log4cplus::initialize();
// register our stuff
log4cplus::spi::LayoutFactoryRegistry& reg = log4cplus::spi::getLayoutFactoryRegistry();
LOG4CPLUS_REG_PRODUCT (reg, "myNamespace::", MyPatternLayout, myNamespace::, log4cplus::spi::LayoutFactory);
log4cplus::PropertyConfigurator::doConfigure(Logger::mConfigFile);
You can then use the layout in the config as
log4cplus.appender.STDOUT.layout = log4cplus::MyPatternLayout #example 1
or
log4cplus.appender.STDOUT.layout = myNamespace::MyPatternLayout #example 2
Simple enough, right? I wish the log4cplus had a documentation closer to the .log4j one

Sitecore TDS Multi-Project properties base template reference not working for me

I am trying to set multi-project properties exactly like how it says in this link/article with base template reference to another TDS project. http://hedgehogdevelopment.github.io/tds/chapter4.html#multi-project-properties
Similar to the above link I have TDS Project TDS A that generates code in project X and TDS Project B (Base templates) that generates code in project Y. Project X references Y and TDS Project A references Project B in the Multi-project properties setting.
Sounds like I am doing what the article says. But the code generated from the TDS project A is not able to generate references to code generated by TDS Project B. To give an example of whats happening: So the right behavior is that class generated in Project X say Class D should inherit from base class say Class Base from Project Y, instead it creates its own version of fully qualified namespace for Class Base that does not exists. It uses its own assembly namespace ProjectX.tree.structure.BaseClass, when it should be ProjectY.tree.structure.BaseClass.
Has anyone got this to work. Am I missing something ?
I have got it to work by tweaking the T4 templates, but that's not the best solution
Thanks
Someone on the team helped me with this. This is not the best solution but should work if you have a setup as defined above. Trick is to modify the below method in the Helpers.tt template. Add the line marked with the comment. Should be able to extend this little further to not hardcode the base project namespace. Will post if I get around to figuring that.
public static string GetNamespace(string defaultNamespace, SitecoreItem item, bool includeGlobal = false)
{
List<string> namespaceSegments = new List<string>();
// add the following line
namespaceSegments.Add(!item.ReferencedItem ? defaultNamespace : "[BaseProjectNameSpace]");
namespaceSegments.Add(item.Namespace);
string #namespace = AsNamespace(namespaceSegments); // use an extension method in the supporting assembly
return (includeGlobal ? string.Concat("global::", #namespace) : #namespace).Replace(".sitecore.templates", "").Replace("_", "");
}
This post is pretty old, however I believe that I have found a solution. I started digging through the GlassV5Item.tt. When the template generates the inheritance string, it calls a method GetObjectInheritanceDefinition(DefaultNamespace, template, true, (string s) => AsInterfaceName(s)). That method looks like this:
<#+
/// <summary>
/// Gets the inheritance string for the generated template
/// </summary>
/// <param name="defaultNamespace">The default namespace.</param>
/// <param name="template">The template to get the bases for.</param>
/// <param name="nameFunc">The function to run the base templates names through.</param>
/// <returns></returns>
public static string GetObjectInheritanceDefinition(string defaultNamespace, SitecoreTemplate item, bool includeLeadingComma, Func<string, string> nameFunc)
{
if (item.BaseTemplates.Count > 0)
{
return string.Concat(includeLeadingComma ? ", " : "",
item.BaseTemplates
.Select(bt => GetFullyQualifiedName(defaultNamespace, bt, nameFunc)) // select the name of the template with an 'I' prefix
.Aggregate( (total,next) => total + ", " + next) // basically a string.join(string[], '')
);
}
return "";
}
The offending section of code is the .Select( bt => GetFullyQualifiedName(defaultNamespace, bt, nameFunc)).
The template makes no attempt to resolve the namespace of the base template. I resolved this by changing the select, as follows:
.Select(bt => GetFullyQualifiedName(bt.TargetProjectName, bt, nameFunc))
I'm not sure if TargetProjectName is the best property to use, but since our project is Helix based, the TargetProjectName name and the namespace of that project match.
The biggest key here, is that the inherited namespace is being derived from the item, not from a parameter that's hard-coded, as you called out as an issue.
I hope this helps!

Dynamically create the structure and variables of a class based on user input in c++

I'm new to the site (and to c++) so please forgive me if this is a basic question - I've googled and looked through this site without success so far, so any help anyone can provide would be hugely appreciated.
I'd like to add some functionality to an app, that allows a user to fully define the structure and contents of an object. For example, user would be presented with a configuration screen that allows them to list each property of the object - given my limited knowledge I've assumed this might be achieved by using a class:
Class Name: CustomClassName
Class Property 1: property1Name property1DataType property1DefaultValue
...
Class Property n: propertynName propertynDataType propertynDefaultValue
The user would then be able to hit a button to save their custom configuration, and the program could then reference that configuration as a Class:
class CustomClassName
{
property1DataType property1Name = property1DefaultValue;
...
propertynDataType propertynName = propertynDefaultValue;
}
I'm not even sure this is possible using Classes, so if there's another mechanism that facilitates this I'm open to suggestions!
You can't create classes in runtime, but since dynamic typing is in essence a subset of static typing, you can fake it.
Start with the Property type1:
using Property = variant<int, float, string>;
A simple "dynamic" class could look like this:
class DynamicClass {
std::map<std::string, Property> properties;
public:
Property const& operator[](std::string const&) const
Property operator[](std::string const&);
};
Use:
DynamicClass d;
d["myInt"] = 5;
1 Example implementation. Internals of variant should be tailored for your specific purpose. If you need an open variant, where you don't know all of the possible types beforehand, this gets more complicated, calling for something like any.

loading classes with jodd and using them in drools

I am working on a system that uses drools to evaluate certain objects. However, these objects can be of classes that are loaded at runtime using jodd. I am able to load a file fine using the following function:
public static void loadClassFile(File file) {
try {
// use Jodd ClassLoaderUtil to load class into the current ClassLoader
ClassLoaderUtil.defineClass(getBytesFromFile(file));
} catch (IOException e) {
exceptionLog(LOG_ERROR, getInstance(), e);
}
}
Now lets say I have created a class called Tire and loaded it using the function above. Is there a way I can use the Tire class in my rule file:
rule "Tire Operational"
when
$t: Tire(pressure == 30)
then
end
Right now if i try to add this rule i get an error saying unable to resolve ObjectType Tire. My assumption would be that I would somehow need to import Tire in the rule, but I'm not really sure how to do that.
Haven't use Drools since version 3, but will try to help anyway. When you load class this way (dynamically, in the run-time, no matter if you use e.g. Class.forName() or Jodd), loaded class name is simply not available to be explicitly used in the code. I believe we can simplify your problem with the following sudo-code, where you first load a class and then try to use its name:
defineClass('Tire.class');
Tire tire = new Tire();
This obviously doesn't work since Tire type is not available at compile time: compiler does not know what type you gonna load during the execution.
What would work is to have Tire implementing some interface (e.g. VehiclePart). So then you could use the following sudo-code:
Class tireClass = defineClass('Tire.class');
VehiclePart tire = tireClass.newInstance();
System.out.println(tire.getPartName()); // prints 'tire' for example
Then maybe you can build your Drools rules over the interface VehiclePart and getPartName() property.
Addendum
Above make sense only when interface covers all the properties of dynamically loaded class. In most cases, this is not a valid solution: dynamically loaded classes simply do not share properties. So, here is another approach.
Instead of using explicit class loading, this problem can be solved by 'extending' the classloader class path. Be warn, this is a hack!
In Jodd, there is method: ClassLoaderUtil.addFileToClassPath() that can add a file or a path to the classloader in the runtime. So here are the steps that worked for me:
1) Put all dynamically created classes into some root folder, with the respect of their packages. For example, lets say we want to use a jodd.samples.TestBean class, that has two properties: number (int) and a value (string). We then need to put it this class into the root/jodd/samples folder.
2) After building all dynamic classes, extend the classloaders path:
ClassLoaderUtil.addFileToClassPath("root", ClassLoader.getSystemClassLoader());
3) load class and create it before creating KnowledgeBuilder:
Class testBeanClass = Class.forName("jodd.samples.TestBean");
Object testBean = testBeanClass.newInstance();
4) At this point you can use BeanUtils (from Jodd, for example:) to manipulate properties of the testBean instance
5) Create Drools stuff and add insert testBean into session:
knowledgeSession.insert(testBean);
6) Use it in rule file:
import jodd.samples.TestBean;
rule "xxx"
when
$t: TestBean(number == 173)
then
System.out.println("!!!");
end
This worked for me. Note that on step #2 you can try using different classloader, but you might need it to pass it to the KnowledgeBuilderFactory via KnowledgeBuilderConfiguration (i.e. PackageBuilderConfiguration).
Another solution
Another solution is to simply copy all object properties to a map, and deal with the map in the rules files. So you can use something like this at step #4:
Map map = new HashMap();
BeanTool.copy(testBean, map);
and later (step #5) add a map to Drools context instead of the bean instance. In this case it would be even better to use defineClass() method to explicitly define each class.