I am new to C++/Cli, actually in the C# project I have string[] which I converted to array, Now I need to pass this unmanaged array into the native CPP file, i.e I want to convert this "array" to std::string*. How I can do that. I tried this below:
void functionA(cli::array^varA){
cli::pin_ptr<System::String^>varA_value = &varA[0];
std::string* varA_value_final = varA_value;
}
But it gives error saying: a value of type cli::pin_ptr cannot be used to initialize entity of type std::string*
The managed class System::String is completely different from the unmanaged class std::string. The classes are completely different, and store completely different data. You cannot get a pointer to one and pretend it's the other.
Iterate over the cli::array<System::String^>, convert each element, and stick the results in a std::vector<std::string> or other unmanaged container. Grab a pointer to the first element. Use marshal_as<std::string>() to convert each element.
Related
I am passing an array of C# objects to a managed C++ DLL. The C# class is defined by:
public class LatLonPointType
{
public double Lat; // Latitude.
public double Lon; // Longitude.
}
I pass an array of LatLonPointTypes to a function in a managed C++ DLL. By trial and error I found that I can pass this to the C++ function using a function argument declared as:
array <LatLonPointType^> ^PolygonPoints
The following C++ code will extract an element of type LatLonPointType ^.
LatLonPointType ^a = PolygonPoints[0];
My questions are:
I have used C++ a number of years ago, this seems to be similar to the reference declaration &. Is there a good reference to ^?
In the above example, how would I convert a (LatLonPointType ^) to a (LatLonPointType) value?
To clarify:
If I have:
LatLonPointType ^a = PolygonPoints[i];
How would I get a.Lat and a.Lon?
Would I use a->Lat and a->Lon?
According to this answer, this hat character, aka ^, creates a managed pointer, that will be garbage collected, not necessarily by you. For example, if you were to create a native object using new, it would look like this:
Object* obj = new Object();
But if you were to use a managed pointer, the syntax would change to:
MObject^ mobj = gcnew MObject();
Currently, I couldn't find how to convert a managed pointer to the object itself, but if you want to convert it to a non managed pointer to the object, see this answer.
EDIT
To access members of the class, such as Lon, you can do this:
//Get method
double i = PolygonPoints[n]->Lon;
//Set method
PolygonPoints[n]->Lon = number;
I have been trying to create a handle to a structure type because I need a pinned pointer to it, but I am getting the error "Object contains non-primitive or non-blittable data"
My structure looks like this:
[StructLayout(LayoutKind.Sequential)]
public struct MyStruct
{
[MarshalAs(UnmanagedType.U1)]
public bool Test;
}
Now, when I call,
var mystruct = new MyStruct();
var handle = GCHandle.Alloc(mystruct, GCHandleType.Pinned);
I get the error "Object contains non-primitive or non-blittable data". Now I understand that the bool field is a non-blittable type. But I was under the impression that by adding the MarshalAs attribute, I could tell the marshaller how to convert the type. (I also tried UnmanagedType.Bool)
This structure has to be defined globally, because it is needed throughout my class. The only reason I need the pointer is because I have an unmanaged API that must pass this structure as a pointer. Then I have to get that structure in a callback and read/update members.
So this is the basic scenario.
Structure is created globally in a managed class
Pointer to structure is obtained
Pointer to the structure is passed into the API
The API calls a static method callback where I then need to get my structure and read/update members.
I tried to use Marshal.StructureToPtr but this only creates a copy, so if in my managed class I update the member, when the callback is raised, the updated value is not there.
Does anyone know how I can get a pinned pointer to my structure so I can read/modify the public members and have them available in the callback?
Thanks
You've got more than one problem here. Using a struct is highly inadvisable. It will get boxed before the GCHandle.Alloc() call and that boxed object gets pinned. You cannot see any updates to it through your mystruct variable. Use a class instead.
And avoid bool, it is a non-blittable type due to its highly variable implementation. It is 4 bytes in C, 1 byte in C++, 2 bytes in COM. Just make it a byte instead. You can write a property to get it back to a bool.
So:
[StructLayout(LayoutKind.Sequential)]
public class MyStruct
{
private byte _test;
public bool Test {
get { return _test != 0; }
set { _test = value ? 1 : 0; }
}
}
You're right that you're telling the marshaller how to marshal the type.
But that won't do you any good when you then attempt to bypass the marshaller.
You need to decide whether you want to use the marshaller, or whether you want the unmanaged code to directly write into managed memory.
If you want to use the marshaller:
Generally, a good way to handle this is to use it in both directions. You can use Marshal.StructureToPtr (as you've found), call the external function, and then use Marshal.PtrToStructure to convert it back into your managed representation.
Or you can use methods that are set up in such a way that marshalling happens automatically, without you needing to specify this manually. For example, calling a native method taking a ref MyStruct parameter will allow for that to happen.
If you don't want to use the marshaller:
Don't use any types that require marshalling. As Hans Passant comments, use a different type instead, byte would probably be a good choice.
(I'll refrain from commenting on the advantages and disadvantages of using structs here, except that the points already made about it are well worth reading and understanding.)
here is the situation: I want to call a method from a C++ module, and pass an array to it:
x.Method(array, ...)
x is a C# object. I would suppose that I could change the array and fill it with my own data - but it seems not be the case (?)
How should I pass the array by reference and change its content in the method?
Thank you in advance,
cheers.
Yes, if you want to alter the array beyond just altering its elements (i.e. adding or removing elements) then you have to pass it by reference. The C# declaration would be:
public void Method(ref Mumble[] arg)
Which isn't great syntax. The garbage collector makes it easy to return an array as the function return value:
public Mumble[] Method(Mumble[] input)
But consider a List<Mumble> instead.
You don't need to pass the array by reference. Array is a reference type, so if you pass the array to the method, you're actually passing a reference to it. The method can change the content of the array pointed by the reference, but cannot change the reference itself (i.e. it can't make it point to a different array). If you were passing the array by reference, the method would be able to change the reference to the array, but that's probably not what you're looking for if you just want to fill an existing array.
I suggest you have a look at this article for more details
I use 3rd party COM to find faces in a picture. One of the methods has the following signature, from SDK:
long FindMultipleFaces(
IUnknown* pIDibImage,
VARIANTARG* FacePositionArray
);
Parameters: pIDibImage[in] - The image
to search.
FacePositionArray[out]- The array of
FacePosition2 objects into which face
information is placed. This array is
in a safe array (VARIANT) of type
VT_UNKNOWN. The size of the array
dictates the maximum number of faces
for which to search.
which translates into the following C# method signature (from metadata):
int FindMultipleFaces(object pIDibImage, ref object pIFacePositions);
Being optimistic I call it the following way but get an exception that the memory is corrupt. The exception is thrown only when a face is present in the image.
FacePosition2[] facePositions = new FacePosition2[10];
object positions = facePositions;
int faceCount = FaceLocator.FindMultipleFaces(dibImage, ref positions);
What's the right way to pass SAFEARRAY to unmanaged code?
It's something like you initialize an array using Marshal.AllocCoTaskMem and then use Marshal.Copy to copy it to unmanaged memory and the pass an IntPtr pointing to the array into the COM method.
In general, look at the Marshal class:
http://msdn.microsoft.com/en-gb/library/system.runtime.interopservices.marshal.aspx
Oops, it seems it only needed from me to initialize the array because FacePosition2 was not a struct but class and it was not initialized automatically as I though it would. This piece was missing:
for (var i = 0; i < facePositions.Length; i++)
{
facePositions[i] = new FacePosition2();
}
There are more sophisticated method, but opinion is more correct:
change this signature Interop, so, he looks like taking an array.
Accessing a SafeArray Result from a COM Call in C#
Default Marshaling for Arrays
Correcting Common Interop Assembly Problems
I have a COM object that I'm trying to use from C++ (not .NET), and all of the example programs and manual are written assuming the use of C#.NET or VB.NET. COM is new to me so I'm a bit overwhelmed. I'm using #import on the TLB but am struggling to deal with the variants that are used as parameters. I have one particular method, that according to the docs and the example programs in C#.NET, is supposed to return an object[]. Then I'm supposed to cast the first entry in this array to a ControlEvent which then tells me what to do with the rest of the objects in the array. The C#.NET example looks like:
object [] objEvent = (object []) Ctl.GetEvent();
ControlEvent ev = (ControlEvent) objEvent[0];
In my case, GetEvent is returning me a _variant_t and I need to know how to convert this to an object[] so that I can further process. Its not clear to me even how I express 'object' in C++. I see _variant_t documentation showing me a million things I can convert the variant to, but none of them seem to be converting to anything I can use. I'm hoping for some assistance converting the above C#.NET code to Visual C++
Thanks.
Typically, you look at the vt member of the variant to see what type of thing it actually is. In this case I would expect it to be an array, so you would expect that the vartype would be some variation on VT_ARRAY (usually it is bitwise OR'ed with the type of the members). Then, you get the parray member which contains the SAFEARRAY instance that actually holds the array, and use the normal safe array functions to get the data out of the array.
I haven't done this, but from reading the documentation for the _variant_t class (and the comments below which corrected my original post), I think you should read the vt field of the _variant_t instance (actually the VARTYPE vt field of the VARIANT instance: the _variant_t instance directly derives from VARIANT) to see what type of thing it contains, as described in the reference documentation for the VARIANT struct. One you know what type of thing is contained in the variant, use the corresponding type-specific operator to read it.
You'll be in for some hurt if you try to use COM without understanding it (and you may want a book which describes that); you may well need to know about the IUnknown interface and the AddRef method, for example.