We are in the process of converting C# code to C++, but we need to do so in phases. I am at a point now where I need to instantiate several native objects from within managed code. These native objects I cannot change, and their declaration looks like this:
public class NativeA();
public class NativeB(std::shared_ptr<NativeA> obj);
Both NativeA and NativeB need to be instantiated from managed code as:
void main() {
ManagedA ObjectA = gcnew ManagedA();
ManagedB ObjectB = gcnew ManagedB(ObjectA);
}
The problem comes in with getting the shared_ptr of NativeA in the constructor of NativeB. Niether NativeA nor NativeB will be manipulated in managed code, they just need to be instantiated. Ideally, something like this:
public ref class ManagedA {
public:
ManagedA() { _object = new NativeA(); }
~ManagedA() { delete _object; }
NativeA * Get() { return _object; }
private:
NativeA *_object;
};
public ref class ManagedB {
public:
ManagedB(ManagedA^ objectA ) {
_object = new NativeB(std::make_shared<NativeA>(*objectA->Get());
}
~ManagedB() { delete _object; }
private:
NativeB *_object;
};
But, this is not allowed in c++/cli because native types are declared as private. Defining #pragma make_public(NativeA) does not solve this either.
My intent is not to work with the native objects in managed code, they just need to be instantiated, so I really don't care about trying to marshal the native pointers and deal with .NET GC if I don't have to, and I don't want to perform a copy. I just want to wrap the classes in order to pass them around.
Is there a clean and simple way to do this?
It appears that the answer was not due to a syntax or usage problem. The two managed objects were in different DLLs and could not be passed across them via .NET. Once the code was compiled in the same project, the issue was resolved.
Although the error message indicated the problem was an accessibility issue in VS 2015, and because it reported it during the link phase, I suspect the cause was because the linker would not have known about the implementation of the NativeA in NativeB without declaring an extern. Being wrapped in CLR, it surfaced as a different issue.
Related
I'm trying to send a QStandardItemModel-derived object to PythonQt, but I'm a little confused on how it needs to be sent. When I was using boost::python I had several controls like boost::noncopyable to ensure I wasn't recreating this object, but sharing it with python. I also had constructs to provide a boost shared pointer to python from inside python.
class Scene : public boost::enable_shared_from_this<Scene>, public QStandardItemModel
In PythonQt, however, I'm not sure what's available. The function call takes a QVariantList for all the function parameters.
QVariant PythonQt::call(PyObject* object, const QString &callable, const QVariantList &args = QVariantList))
What I'm confused about now is how to get my object to python via a QVariant. Since its derived from QStandardItemModel, I figured it would already be register
void MyObject::someFunction(QString fileName)
{
QVariant myObjectV = qVariantFromValue(this);
// send to python
...
}
But this gives me the following error:
'qt_metatype_id' : is not a member of 'QMetaTypeId<MyObject>'
I've tried registering it after I declare my class, but this throws a different error.
class MyObject : public QStandardItemModel
{
Q_OBJECT
...
};
Q_DECLARE_METATYPE(MyObject)
QStandardItemModel::QStandardItemModel(const QStandardItemModel&) is private within this context.
I actually get the error twice--once in header where I add the Q_DECLARE_METATYPE and in another header, which has a class which always derives from QStandardItemModel but is otherwise unrelated.
Is Q_DECLARE_METATYPE even the correct way to go about converting this object to a QVariant?
BOOST_PYTHON_MODULE(scene)
{
class_("Scene");
}
Yes, by default, QVariant can take one of te following types - http://doc.qt.io/qt-4.8/qvariant.html#Type-enum - and they are not enough for your task. You should declare additional types by yourself via qmetatype system. Thus you shoud call qRegisterMetaType() function.
Suppose I have the following simple wrapper of a NativeClassInstance.
public ref class Wrapper
{
private:
NativeClass *_wrapped;
public:
Renderer()
{
_wrapped = new NativeClass();
}
~Renderer()
{
delete _wrapped;
}
operator NativeClass*()
{
return _wrapped;
}
}
Now, I want to create an instance of Wrapper from C# with Wrapper wrapper = new Wrapper() and use it in another native functionalities wrapper that resides in another assembly with Helper.Foo(wrapper) (nothing strange having other functionalities not directly related to the wrapped classes in another assembly, IMO):
// Utilities is in another Assembly
public ref class Helper
{
public:
static Foo(Wrapper ^wrapper)
{
// Do something in native code with wrapper->_wrapped
}
}
The results with the implicit user conversion is:
candidate function(s) not accessible
If I make _wrapped public it is:
cannot access private member declared in class ...
Now, I've learnt that native type visibility is private outside of the assembly. So, how I'm supposed to use the wrapped entity in native code outside the assembly it's defined? I've read of make_public but you can't use with template types so it seems very limiting in the general case. Am I missing something? Is there a more correct solution?
I haven't been able to successfully expose native types using make_public, however a solution I have used is to put NativeClass in its own native DLL and then a) reference the native DLL from both assemblies; and b) pass the pointer to the native class around as an IntPtr.
Under the above scenario, instead of having an operator NativeClass* you might use a property such as
property IntPtr WrappedObject {
IntPtr get() { return IntPtr(_wrapped); }
}
You then retrieve NativeObject in you helper assembly by
static void Foo(Wrapper ^wrapper)
{
NativeObject *_wrapped
= static_cast<NativeObject*>(wrapper->WrappedObject.ToPointer());
// ... do something ...
}
If you use make_public, your solution of making _wrapped public should work (it would obviously be best to make a public accessor instead). Regarding your comment "I've read of make_public but you can't use with template types so it seems very limiting in the general case." I agree--read here for the workaround I used:
http://social.msdn.microsoft.com/Forums/en-US/vclanguage/thread/b43cca63-b0bf-451e-b8fe-74e9c618b8c4/
More related info:
Best workaround for compiler error C2158: make_public does not support native template types
Good luck!
I am loading an swf created in flash professional cs5 via the loader class into a flex 4.1 application. The flash file contains multiple movieclips that are exported for actionscript and those movieclips exist in many instances throughout the movie.
Iterating through everything, comparing class types seems to be the most easy but also the most redundant way to solve this. Is there any way of using the class name as a kind of global selector to access the clips?
I could also make the sub-clips in the flash listen for an event on which they perform an action, but I am not really sure what might be best.
In cases like these, I find that a good way to solve the problem is to create a statically accessable class that manages instances of other classes that are registered with it on instantiation. As an example...
public class GlobalStopper{
private static var clips:Array = [];
public static function add(mc:MovieClip):void{
clips.push(mc);
}
public static function stop():void{
var mc:MovieClip;
for(var i:int = 0, ilen:int = clips.length ; i < ilen ; i++){
mc = clips[i] as MovieClip;
if (mc) mc.stop();
}
}
}
and...
public class GloballyStoppableMovieClip extends MovieClip{
public function GloballyStoppableMovieClip(){
GlobalStopper.add(this);
}
}
Any and all instances of GloballyStoppableMovieClip are instantly registered with the GlobalStopper, so calling
GlobalStopper.stop();
...will stop all registered movieclips.
You can add in any other functions you want. Furthermore, instead of having add accept MovieClip instances, you could have it accept IStoppable or IPlayable objects that implement public functions stop() and play() that your movieclip subclass (or non-movieclip object that also might need to stop and play!) then implements.
But as for jQuery-like selectors? Not really the way I'd handle this particular issue.
i guess typing it out did the trick. i used the event solution:
in the root timeline i placed a function like this:
function cause():void {
dispatchEvent(new Event("do stuff",true));
}
and in the library clip's main timeline goes:
DisplayObject(root).addEventListener("do stuff", function (e:Event=null) {
... whatever ...
});
this is dirty but you get the idea.
Based on this article, I've written a custom class which implements the Watin.Core.interfaces.IFindByDefaultFactory, but I don't think I'm correctly assigning it to the watin settings, because it is never used.
Basically, Where/when should I assign to the Settings.FindByDefaultFactory? I've tried in my test Setup, and the text fixture's constructor, but neither seem to cause my custom class to be used. The tests still run and work, but I have to use the full asp.net ID's.
I'm using Watin 2.0.15.928 in VS2008 from nUnit 2.5.2.9222. I am running visual studio as administrator, and tests run sucessfully as long as I don't rely on my custom find logic.
Here's what the start of my text fixture looks like, where I set the FindByDefaultFactory
namespace Fundsmith.Web.Main.BrowserTests
{
[TestFixture]
class WatinHomepageTests
{
private IE _ie;
[SetUp]
public void Setup()
{
Settings.FindByDefaultFactory = new FindByAspIdFactory();
_ie = new IE("http://localhost/somepage.aspx");
}
//etc etc...
And this is what my custom Find By Default factory looks like (simplified), unfortunately, it's never called.
using System.Text.RegularExpressions;
using WatiN.Core;
using WatiN.Core.Constraints;
using WatiN.Core.Interfaces;
namespace Fundsmith.Web.Main.BrowserTests
{
public class FindByAspIdFactory : IFindByDefaultFactory
{
public Constraint ByDefault(string value)
{
// This code is never called :(
// My custom find by id code to cope with asp.net webforms ids...
return Find.ById(value);
}
public Constraint ByDefault(Regex value)
{
return Find.ById(value);
}
}
}
Edit: Extra information after the fact.
Based on me fuguring this out, (see answer below), It turns out that the way I was consuming Watin to find the elements was wrong. I was explicitly calling Find.ById, rather than letting the default action occur. So I'd reassigned the default but was then failing to use it!
[Test]
public void StepOneFromHomepageShouldRedirectToStepTwo()
{
_ie.TextField(Find.ById("textBoxId")).TypeText("100");
//Other test stuff...
}
Right, I've figured this one out, and it was me being an idiot and explicitly calling the Find.ById method, rather than letting the default action occur. It seems the test setup is a fine place to set the FindByDefaultFactory.
ie, I was doing this (wrong):
[Test]
public void StepOneFromHomepageShouldRedirectToStepTwo()
{
_ie.TextField(Find.ById("textBoxId")).TypeText("100");
//Other test stuff...
}
When I should have been simply doing this. (Without the explicit "Find.ById")
[Test]
public void StepOneFromHomepageShouldRedirectToStepTwo()
{
_ie.TextField("textBoxId").TypeText("100");
//Other test stuff...
}
Not only was this me being stupid, but I didn't include this in my original question, so it would have been impossible for anyone else to figure it out for certain. Double slaps for me.
I'm using Python+PyAMF to talk back and forth with Flex clients, but I've run into a problem with the psudo-Enum-Singletons I'm using:
class Type {
public static const EMPTY:Type = new Type("empty");
public static const FULL:Type = new Type("full");
...
}
When I'm using locally created instances, everything is peachy:
if (someInstance.type == Type.EMPTY) { /* do things */ }
But, if 'someInstance' has come from the Python code, it's instance of 'type' obviously won't be either Type.EMPTY or Type.FULL.
So, what's the best way to make my code work?
Is there some way I can control AMF's deserialization, so when it loads a remote Type, the correct transformation will be called? Or should I just bite the bullet and compare Types using something other than ==? Or could I somehow trick the == type cohesion into doing what I want?
Edit: Alternately, does Flex's remoting suite provide any hooks which run after an instance has been deserialized, so I could perform a conversion then?
Random thought: Maybe you could create a member function on Type that will return the canonical version that matches it?
Something like:
class Type {
public static const EMPTY:Type = new Type("empty");
public static const FULL:Type = new Type("full");
...
// I'm assuming this is where that string passed
// in to the constructor goes, and that it's unique.
private var _typeName:String;
public function get canonical():Type {
switch(this._typeName) {
case "empty": return EMPTY;
case "full": return FULL;
/*...*/
}
}
}
As long as you know which values come from python you would just convert them initially:
var fromPython:Type = /*...*/
var t:Type = fromPython.canonical;
then use t after that.
If you can't tell when things come from python and when they're from AS3 then it would get pretty messy, but if you have an isolation layer between the AS and python code you could just make sure you do the conversion there.
It's not as clean as if you could control the deserialization, but as long as you've got a good isolation layer it should work.