System.NullReferenceException when using gcroot - c++-cli

Turns out this error had nothing to do with gcroot - I connected some constructors shoddily and lost the instantiated object on the way.
For the record, all versions of the code below worked after this fix, but adding the simple Wrapper class allows you to use & and * operators on the wrapped object, which gcroot forbids. I am using the version outlined in the third code block below.
I am trying to use some measuring instruments via a .dll, but I am having problems with the implementation. Writing all the code into the main.cpp and using the object like this works fine:
#using "M3D_FP_USB.dll"
int main(){
M3D_FP_USB ^obj = gcnew M3D_FP_USB;
obj->Connect();
...
}
However, when I put it into a class and wrap it with gcroot, I get an "Unhandled Exception: System.NullReferenceException: Object reference not set to an instance of the object" on execution.
class User{
...
public:
User();
gcroot<M3D_FP_USB^> obj;
}
User::User(){
obj = gcnew M3D_FP_USB;
obj->Connect();
...
}
I suspect that the gcroot or it being called inside the unmanaged class might prevent the instruments from accessing the M3D_FP_USB object. I tried adding a managed Wrapper class, and give a handle to the Wrapper object to the User class. That didn't solve the problem, though.
class User{
...
public:
gcroot<Wrapper^> wobj;
}
ref class Wrapper{
...
public:
M3D_FP_USB^ iobj;
...
}
Wrapper::Wrapper(){
iobj = gcnew M3D_FP_USB;
iobj->Connect();
...
}
The new code I have looks like this, but I couldn't test it with the instruments yet. I will update when I get the chance.
Wrapper::Wrapper(M3D_FP_USB^ obj){
iobj = obj;
iobj->Connect();
...
}
int main(){
M3D_FP_USB ^obj = gcnew M3D_FP_USB;
Wrapper Ex(obj);
}

Does the exception also happen if you make the class managed and just declare the handle directly? Like:
ref class User
{
public:
M3D_FP_USB^ obj;
...
};
Though I don't see why it wouldn't work the way you're doing it...

Related

How to properly use a forward declared class in c++ cli?

I am getting error code C2512 which is no appropriate default constructor available. However it appears to me that everything should be working so I am a bit confused on how to get this to compile.
Here is the header file code:
namespace MyNamespace
{
ref class ForwadDeclaredClass;
public ref class MyClass
{
public:
MyClass();
// ...
private:
ForwadDeclaredClass^ fc;
}
}
Now in my cpp file I define the forwarded class and try to use it in the constructor for MyClass.
using namespace MyNamespace;
//...
public ref class ForwardDeclaredClass
{
public:
ForwardDeclaredClass()
{
}
}
MyClass::MyClass()
{
// Compiler complains with error code here
fc = gcnew ForwardDeclaredClass();
}
I know I have to be missing something simple but I am just not seeing it. Any help would be appreciated.
At first glance, it looks like your namespaces are off.
In the header file, you're declaring ForwardDeclaredClass and MyClass inside MyNamespace.
In the cpp file, you're using MyNamespace, but the code you're writing isn't inside the namespace.
It looks like you need to enclose most of the contents of the cpp file in a namespace MyNamespace { block.

How to instantiate c++ objects with QJSEngine

Is it possible to declare a C++ class to QJSEngine (the engine for QML) so objects of that class can be instantiated from javascript?
The only solution I can come up so far is to create a factory method with Q_INVOKABLE that returns an object using QJSEngine ::newQObject()
Thanks!
How about using Qt.createQmlObject()? The problem is you need to supply a parent item when creating an object. The other being unable to call non-default constructor.
// C++ class (from http://doc.qt.io/qt-5/qtqml-cppintegration-definetypes.html)
class Message : public QObject
{
Q_OBJECT
Q_PROPERTY(QString author READ author WRITE setAuthor NOTIFY authorChanged)
Q_PROPERTY(QDateTime creationDate READ creationDate WRITE setCreationDate NOTIFY creationDateChanged)
public:
// ...
};
// Register the C++ class to be used by QML
qmlRegisterType<Message>("com.mycompany.messaging", 1, 0, "Message");
// Create C++ object from QML JavaScript
var msg = Qt.createQmlObject('import com.mycompany.messaging 1.0; Message {}', parentItem);
msg.author = "Kate";

Runtime exception when calling C++/CLI derived class

Edited by the OP 5 August 2014:
Much simplified code:
public ref class CXmlWriter : public System::Xml::XmlTextWriter
{
public:
CXmlWriter(System::String ^sFilename) : XmlTextWriter(sFilename, System::Text::Encoding::Unicode)
{
}
~CXmlWriter()
{
}
};
Call a function containing code that instantiates CXmlWriter (you don't have to execute that instantiation code) and you get the exception.
Comment out the destructor and you don't get the exception. Making the destructor virtual doesn't fix it.
End of edit
I am using Version 4 of the .NET framework.
I have C++/CLI classes CXmlWriter derived from System::Xml::XmlTextWriter and CMinMaxXmlWriter derived from CXmlWriter.
Implementation is pretty simple for both classes and everything compiles without error. However, when I try to instantiate CMinMaxXmlWriter at runtime I get a TypeLoadException with the error message:
Declaration referenced in a method implementation cannot be a final method
with a mention of CXmlWriter
This used to work without any problem in Version 2 of the framework.
Here's the header for CXmlWriter:
public ref class CXmlWriter : public System::Xml::XmlTextWriter
{
public:
CXmlWriter(System::String ^sFilename);
~CXmlWriter();
!CXmlWriter() {}
virtual bool Open();
virtual void Close() override;
virtual bool WriteValueAndAttribute(System::String ^sElementName, System::String ^sElementValue, System::String ^sAttrName, System::String ^sAttrValue);
virtual bool WriteValueAndAttribute(System::String ^sElementName, double dElementValue, System::String ^sAttrName, System::String ^sAttrValue);
protected:
bool m_bIsOpen;
};
CMinMaxXmlWriter is defined in a very similar way.
Please can someone explain why the exception occurs and what I should do to avoid it.

Cannot use managed event/objects in unmanaged code error c3265, c2811

Native C++ library that I am using in C++/CLI project raises events giving me results,
If I try to handle the event by extending the unmanaged event, it says the ref class can only extend ref class.
I then tried to create a native event but have manged object inside it to collect the results, but I get the error cannot declare managed object in unmanaged class.
Is there anyway to get it done in one of the ways I am trying, or should I declare unmanaged result objects fill them in unmanaged event and then Marshall it ?
Edit:
class MyNativeListener: public NativeEventListener
{
private:
ManagedResultsObject ^_results;
public:
void onEndProcessing(ProcessingEvent *event)
{
_results.Value = event->value;
//Many more properties to capture
}
};
This is what I am trying, I have extended the native event listener to capture the event, but not sure how to capture the results to a managed object.
Edit2
Found this while searching on the same line as suggested by #mcdave auto_gcroot
Your native class needs to store a handle to the managed object instead of a reference to it. You can do this using the gcroot template. If you dig into the gcroot template you will find it uses the GCHandle Structure, which with appropriate static casting can be stored as a void* pointer and so provides a means of storing managed references in native code.
Try expanding your code along the following lines:
#include <vcclr.h>
class MyNativeListener: public NativeEventListener
{
private:
gcroot<ManagedResultsObject^> _results;
public:
void onEndProcessing(ProcessingEvent *event)
{
_results->Value = event->value;
//Many more properties to capture
}
};

C++/CLI I can't add a class to my collection

I am attempting to simply add a FilterInfo class to my FilterInfo collection. I'm having a terrible time trying to understand why the following code keeps throwing the error:
System::Collections::Generic::List::Add'
: cannot convert parameter 1 from
'Ziz::FilterInfo *' to
'Ziz::FilterInfo'
I'm only learning C++/CLI, as I'm a C# developer, and I'm sure it's something simple, but I sure could use some pointers. My stripped code is as follows:
public value class FilterInfo
{
public:
char* Address;
};
public ref class Ziz
{
private:
List<FilterInfo>^ _blockList;
public:
// Constructor
Ziz(){
_blockList = gcnew List<FilterInfo>();
}
List<FilterInfo>^ GetBlockList()
{
for each(_IPFILTERINFO ip in _packetFilter->GetBlockList())
{
// _IPFILTERINFO is the native C++ struct.
FilterInfo* f = new FilterInfo();
_blockList->Add(f);
}
return _blockList;
}
You declared _blockList as
List<FilterInfo>^ _blockList;
but you are trying to add
FilterInfo* f
to it. It cannot work since one is a pointer and the other one is a reference.
I'm not sure how "value" fits in but in
public value class FilterInfo
{
public:
char* Address;
};
You are derefore declaring an unmanaged class
to make it managed, you should use
public ref class FiterInfo
This will allow you to use FilterInfo* without having to manage memory explicitely.
Finally, char* is not so great in C++/CLI, I would recommend using System::String
_blockList->Add(*f);
You have to construct your FilterInfo with gcnew as well. You can't really mix and mash these together without marshaling.
FilterInfo is not FilterInfo*. If you want a List of pointers to FilterInfo, you need to say that List<FilterInfo*>. Since FilterInfo is a value class here though you'll likely just want to skip the new.
FilterInfo fi;
_blockList->Add(fi);
public ref class A
{
};
int main(array<System::String ^> ^args)
{
Console::WriteLine(L"Hello World");
ICollection<A^>^ oCollection = gcnew List<A^>();
oCollection->Add(gcnew A());
return 0;
}