I want to make a C++/CLI wrapper of some C++ class.
The problem is that I want the ref class to be initiated with a reference of the c++ object:
A (A& a);
This works fine as long as it is in the same aseembly and used in the same project.
But when I try to reference that project from a different project, and initiate a ref-class with a reference to an object from there, it won't recognize the types properly, and doesn't recognize the correct constructor.
Any ideas of how to solve this ?
I don't think you will be able to use a reference to the C++ object in this instance, but you can pass a pointer to the C++ object across assembly boundaries by storing it in an IntPtr and then retrieving it using static_cast.
class nativeA; // Pre declaration
A (IntPtr a)
{
nativeA * nativePtr = static_cast<nativeA*>(a.ToPointer());
// Do something with nativeA
}
Related
I'm new to C++ CLI and I still don't get the new pointers and handles.
I have a native function which opens a window. It requires a handle to a parent window:
void open(void* parentHwnd);
How am I supposed to pass a parent window from managed code to this function? I was trying to do something like this:
void managedOpen(Object^ parent)
{
interior_ptr<void> ptr = &*parent);
open(ptr);
}
but the & operator "cannot be used to take the address of an object with a ref class type".
Also should I use pin_ptr instead of interior_ptr?
Picking proper types in an interop scenario is 99% of the battle. You didn't get any help from the existing code, void* is not an appropriate type to use for a window handle. It should be HWND. That ship probably sailed a long time ago.
But on top of the list of types never to use is System::Object. That only ever interops correctly by sheer accident, unless you interop with COM code that uses variants. The appropriate type to store an operating system handle in managed code is IntPtr or SafeHandle. Heavily biased to IntPtr for window handles since there isn't anything safe about them, they'll die beyond your control when the user closes a window.
So this needs to look like this:
void managedOpen(IntPtr parent)
{
open(parent.ToPointer());
}
With the burden on the client code to produce a valid IntPtr. Could be Control.Handle in Winforms or WindowInteropHelper.Handle in WPF, etcetera.
Stuff like System::Object is only passed from managed to unmanaged with intention of passing it back to managed code, such as a managed function calling EnumWindows. But in this case:
In C++/CLI, you can simply pass a pointer to an unmanaged object containing a gcroot<> to the managed object you want to access.
In C#, you use the GCHandle class to obtain an IntPtr and back.
So, I'm a writing a C++/CLI wrapper and I would like it to interact with objects from a referenced, managed (C#) dll. More specifically, in my C++/CLI project, I would like to have classes like this:
public ref class MyClass
{
public:
void InputPoints(array<Point3d^>^ ptsIn);
};
Where, "Point3d" is an object from the referenced, managed dll - call it "MyGeometryDLL.dll". This compiles without any problems, however when I use the wrapper in a C# project (that also references "MyGeometryDLL.dll") , I can't pass Point3d directly to the wrapper, i.e., intellisense detects:
void MyClass.InputPoints(ValueType[] ptsIn);
How would I pass Point3d directly to the wrapper?
So class Point3d is already defined in a C# DLL, correct? In that case, I think it may be an issue of carats.
If it's declared in C# as public struct Point3d, then it's a value type, not a reference type. That means that whenever you use it in C++/CLI, you don't use the ^, and you don't call gcnew. If that's the case, then you need to change the method declaration to this:
void InputPoints(array<Point3d>^ ptsIn); // No carat on Point3d
The reason that C# sees this as ValueType[] is because Point3d^ is a legal type in C++/CLI, but it doesn't exist in C#. A general ValueType is the closest thing, so that's what C# sees.
I am developing a compiler for an object oriented language targeted on a virtual machine I wrote that I am using as a cross platform abstraction layer. I am sort of confused about how inherited methods works. Lets say I had the following lines of C# code.
class myObject : Object {
public int aField;
public override string ToString() {
return "Dis be mah object";
}
public void regularMethod() { }
}
Object test = new myObject();
Console.WriteLine(test.ToString());
Now this would output 'Dis be mah object'. If I called regularMethod however the compiled code would in reality do something like this:
struct myObject {
public int aField;
}
public static void regularMethod(ref myObject thisObject)
{
}
How would the inherited method ToString be handled after compilation? The compiler could not do what I did above with regularMethod, because if it did then 'Dis be mah object' would only be returned when creating myObject types and not plain Object types. My guess is that the struct myObject would contain a function pointer/delegate that would get assigned when a new instance is created.
If you are dealing with static overloading, it is really simple: you bind to the correct implementation when processing the code.
But, if you are working with dynamic overloading, you must decide things at runtime. For this you need to use dynamic dispatch, using the real object type. This is the same thign that is done with method overriding.
Dynamic dispatching is not the same as late binding. Here, you are chosing an implementation and not a name for your operation (despite the fact that this binding will occur at compile time, the implementation will only occur at runtime).
Staticly, you would only bind to implementation of the declared type of the object. It is done at compile time.
The are some mechanisms you could use to achieve the dynamic dispathing, it will dictate your language paradigm.
Is your language typed? Weakly typed?
C++, for instance, offers the two types of dispatch I mentioned. For the dynamic one (which I believe is the one you are interested), it uses a virtual table to do the mapping for one class. Each instance of that class will point have a pointer to that vtable.
Implementing
The vtable (one for all objects of same class) will have the addresses of all dynamicly bound methods. One of those addresses will be fetched from this table when a call is made. Type-compatible objects have tables with addresses with the same offset for the methods of all compatible classes.
Hope I've helped.
I'd like to have a managed com object that exposes methods which accept as arguments objects implementing given interfaces. Something like this
[ComVisible(true)]
[Guid(".....")]
class SomeClass {
public void SomeMethod(ISomeInterface arg)
.....
Apparently ISomeInterface should also be declared ComVisible.
Now I want to consume that COM object in a managed client and call SomeMethod there. The problem is I need to instantiate an object that implements ISomeInterface. If that was a native COM object I'd get an interop assembly generated automatically and that won't be a problem. One cannot generate an interop assembly for managed COM object though.
I see that .NET 4.0 introduces the type equivalence concept. It looks like I could generate an interop manually using the ComImport attribute. But that looks like a pretty nasty job. I guess I could also use the TypeIdentifierAttribute but the documentation on that is vague and it says it's mostly intended for use by compilers.
So are there any other ways to do that?
I have added a class to my program and tested it. I was really surprised that there was any real errors. Here is the code:
#pragma once
#include "Iingredient.h"
#include <string>
#include <vector>
using namespace std;
ref class Recipe{
private:
string partsName;
vector<Iingredient> ing;
public:
Recipe(){}
};
And here are the errors:
Error 23 error C4368: cannot define 'partsName' as a member of managed
'Recipe': mixed types are not
supported c:\users\user\documents\visual studio
2010\projects\smestras2_l1\Recipe.h 10 1 file2_L1
Error 24 error C4368: cannot define 'ing' as a member of managed
'Recipe': mixed types are not
supported c:\users\user\documents\visual studio
2010\projects\smestras2_l1\Recipe.h 11 1 file2_L1
I googled a bit and found out that its about managed and unmanaged code.
How to fix this? Is it related with manged and unmanaged code or not? if so how?
I agree with others: you shouldn't use C++/CLI in most circumstances, you should use C# (or another "normal" managed language) for that (assuming you want to write a .Net application). C++/CLI is useful mostly in special circumstances, like interoperating between managed and unmanaged code.
If you're sure you want use C++/CLI, you can't put native classes into managed ones. But you can put pointers to native classes there:
ref class Recipe{
private:
string* partsName;
vector<Iingredient>* ing;
};
The code above works. But you have to keep in mind that those are normal native C++ pointers and that means you have to manually delete them. To do that property, you should read about how destructors and finalizers work in C++/CLI.
When defining ref class Recipe, you made it managed. But std::string and std::vector are umanaged types. You are trying to declare native variables in managed class, but it is not allowed.
Seems, you are novice in C++. Just, don't use C++/CLI. Consider C#, if you target .Net or unmanaged C++.
You cannot use unmanaged types in a managed class, ref keyword, because the heap and the managed heap are two different types of memory. To solve this specific problem you can use a managed string type (System::String^). The carrot tells the compiler that the type is a handle to a managed class.
Another way of going about this problem is to use pointers, that way the pointer will be on the managed heap, and the actual memory for that object will be in the standard unmanaged heap, which is where Recipe is located.
To construct your Recipe class you would have to do
Recipe^ recipe = gcnew Recipe();
With no idea of c++-cli, I can try and guess that the problem is that you are defining a reference type and trying to use C++ types inside (a std::string field) rather than whatever the equivalent managed type is (String?).
The reason why this can be problematic is that it mixes resource management approaches. Reference types are intended to be used out of a garbage collector, and unless you implement a destructor or IDisposable will just be ignored once proven that the last reference is lost. On the other hand, to be able to manage the memory in the internal field the std::string destructor must be called.