Could you please let me know how to convert CStringArray* to C++/CLI array. I am creating a wrapper dll which needs my data to be converted to unmanaged code. I am able to use basic data types like double * but not for CStringArray *.
Thank you.
Here is the solution
#include <msclr/marshal.h>
#include <msclr/marshal_cppstd.h>
#include <msclr/marshal_atl.h>
CStringArray * myData; //Assume data is already filled
array<String ^> unmanagedData = gcnew array<String ^) (m_nDataCount);
for (int j = 0; j < m_nDataCount; j++)
{
String ^ stepName = marshal_as<String ^> (myData->GetAt(j));
unmanagedData[j] = stepName;
}
Marshaling as is the solution. Thanks to #crashmstr for helping me to crack this
Related
I have a function called TestFunction which I've simplified down for this question... but in essence, I'm getting an error which says, <function-style-cast> cannot convert from 'initializer list' to std::pair<int, int>. Here's my simplified function:
#include <iostream>
#include <map>
void MyClass::TestFunction(cli::array<int>^ ids){
std::multimap<int, int> mymap;
int count = ids->Length;
for (int i = 0; i < count; ++i) {
//fill in the multimap with the appropriate data key/values
mymap.insert(std::make_pair((int)ids[i], (int)i));
}
}
As you can see, it's a really basic function (when simplified), but I get an error when I try to insert the data into the multimap. Does anyone know why?
I'd either use
mymap.insert(std::make_pair((int)ids[i], (int)i));
or
mymap.emplace((int)ids[i], (int)i);
I'm building off of the answer by #CoryKramer. It appears that if I create a temporary variable of type int and then pass that into the multimap.insert() function... that the error is fixed. Here's the new function:
#include <iostream>
#include <map>
void MyClass::TestFunction(cli::array<int>^ ids){
std::multimap<int, int> mymap;
int count = ids->Length;
for (int i = 0; i < count; ++i) {
//fill in the multimap with the appropriate data key/values
int ff = (int)ids[i];
mymap.insert(std::make_pair(ff, (int)i));
}
}
Out of curiousity... does anyone know why this worked?
I'm a newbie currently using c++/cli to wrap a few classes that i have used in my .lib file. And I am in dire need of using "memset" in my c++/cli. Anyone here knows how to use memset in c++/cli code?
The c++ code I'm trying to use in my c++/cli code:
memset(&DeviceInfo, 0, sizeof(FS_DEVICE_INFO));
Here's my c++/cli Code where I get the error when I try to use the same memset line from my c++ code:
bool newIFSWDevice::GetDeviceInfo(PFS_DEVICE_INFO pDevInfo)
{
IFSDevice* pDeviceWheel = nullptr;
FS_DEVICE_INFO DeviceInfo;
int x = 0;
while (nullptr != (pDeviceWheel = newFSDeviceEnumerator::EnumerateInstance(x++)))
{
memset(&DeviceInfo, 0, sizeof(FS_DEVICE_INFO)); //error line
pDeviceWheel->GetDeviceInfo(&DeviceInfo);
if (0 == wcscmp(DeviceInfo.Name, FS_DEVICE_WHEEL_PORSCHE_NAME)
break;
I tried using a for loop instead...
for (int i = 0; i <= sizeof(FS_DEVICE_INFO); i++)
FS_DEVICE_INFO[i] = 0;
But it still gives me an error "expression must have a constant value". Help would be much appreciated! :)
As noted in the comments, you're missing the header file #include <string.h>. See the documentation.
It's also worth noting that your for loop to do the clearing has several problems:
for (int i = 0; i <= sizeof(FS_DEVICE_INFO); i++)
FS_DEVICE_INFO[i] = 0;
sizeof(FS_DEVICE_INFO) gives you the size of that struct in bytes, but FS_DEVICE_INFO[i] indexes into an array of structs: [1] would be the second struct in the array, not the second byte! You would need to cast the pointer to char or something similar.
i <= sizeof(FS_DEVICE_INFO): The <= is incorrect. If the struct is 10 bytes large, you'd end up operating on bytes 0 through 10, which is 11 bytes total, stomping on whatever happened to be after the struct.
FS_DEVICE_INFO[i]: FS_DEVICE_INFO is the name of the class, your local variable is DeviceInfo, so this should be DeviceInfo[i]. This is why you're getting the expression must have a constant value error.
I have a native struct, (which is quite large so I have to use new key word to instantiate, below is just to make a MCVE I cant change the struct as it is provided as external dependencies),
struct NativeStruct
{
char BrokerID[11];
char InvestorID[13];
char InstrumentID[31];
char OrderRef[13];
char UserID[16];
char OrderPriceType;
char Direction;
double LimitPrice;
}
I want to convert NativeStruct to managed object, so I defined a ref struct to mirror it, this also used two enums as below,
public enum struct EnumOrderPriceTypeType
{
AnyPrice = (Byte)'1',
LimitPrice = (Byte)'2',
BestPrice = (Byte)'3',
LastPrice = (Byte)'4',
LastPricePlusOneTicks = (Byte)'5',
LastPricePlusTwoTicks = (Byte)'6',
LastPricePlusThreeTicks = (Byte)'7',
AskPrice1 = (Byte)'8',
AskPrice1PlusOneTicks = (Byte)'9',
AskPrice1PlusTwoTicks = (Byte)'A',
AskPrice1PlusThreeTicks = (Byte)'B',
BidPrice1 = (Byte)'C',
BidPrice1PlusOneTicks = (Byte)'D',
BidPrice1PlusTwoTicks = (Byte)'E',
BidPrice1PlusThreeTicks = (Byte)'F'
};
public enum struct EnumDirectionType
{
Buy = (Byte)'0',
Sell = (Byte)'1'
};
[StructLayout(LayoutKind::Sequential)]
public ref struct ManagedStruct
{
[MarshalAs(UnmanagedType::ByValTStr, SizeConst = 11)]
String^ BrokerID;
[MarshalAs(UnmanagedType::ByValTStr, SizeConst = 13)]
String^ InvestorID;
[MarshalAs(UnmanagedType::ByValTStr, SizeConst = 31)]
String^ InstrumentID;
[MarshalAs(UnmanagedType::ByValTStr, SizeConst = 13)]
String^ OrderRef;
[MarshalAs(UnmanagedType::ByValTStr, SizeConst = 16)]
String^ UserID;
EnumOrderPriceTypeType OrderPriceType;
EnumDirectionType Direction;
double LimitPrice;
};
Then I use StructureToPtr to copy the native object to managed object, and use WriteLine to test if the copy is successful,
NativeStruct *native = new NativeStruct();
ManagedStruct^ managed = gcnew ManagedStruct();
managed->LimitPrice = 95.5;
managed->BrokerID = "666666";
Marshal::StructureToPtr(managed, IntPtr(native), false);
int i;
for (i = 0; i < 11; i++)
Console::Write(native->BrokerID[i]);
Console::WriteLine();
Console::WriteLine(native->LimitPrice);
Console::WriteLine(L"Hello ");
Console::ReadLine();
My question is why LimitPrice is not copied successfuly? I have been battling this for a week, any help will be welcomed. Thanks a lot.
Marshal::StructureToPtr() can only work correctly when the managed and the native struct are an exact match. By far the simplest way to verify this is to check the sizes of the structures, they must be identical. So add this code to your program:
auto nlen = sizeof(NativeStruct);
auto mlen = Marshal::SizeOf(ManagedStruct::typeid);
System::Diagnostics::Debug::Assert(nlen == mlen);
Kaboom. The native struct takes 96 bytes and the managed one takes 104. Consequences are dire, you corrupt memory and that has a lot more unpleasant side effects than the LimitPrice member value getting copied to the wrong offset.
Two basic ways to trouble-shoot this. You can simply populate all of the managed struct members with unique values and check the first member of the native struct that has the wrong value. The member before it is wrong. Keep going until the you no longer get the kaboom. Or you can write code that uses offsetof() on the native struct members and compare them with Marshal::OffsetOf().
Just to save you the trouble, the problem are the enum declarations. Their size in the native struct is 1 byte but the managed versions take 4 bytes. Fix:
public enum struct EnumOrderPriceTypeType : Byte
and
public enum struct EnumDirectionType : Byte
Note the added : Byte to force the enum to take 1 byte of storage. It should be noted that copying the members one-by-one instead of using Marshal::StructureToPtr() is quicker and would have saved you a week of trouble.
I'm trying to use CGAL to do some boolean operations on meshes.
How do I convert from Surface_mesh to Nef_polyhedron_3?
EDIT:
I've tried with this code, but I don't know how to continue...
#include <iostream>
#include <CGAL/Nef_polyhedron_3.h>
#include <CGAL/Simple_cartesian.h>
#include <CGAL/Surface_mesh.h>
using namespace std;
typedef CGAL::Simple_cartesian<double> K;
typedef CGAL::Surface_mesh<K::Point_3> Mesh;
int main()
{
Mesh m;
auto a = m.add_vertex(K::Point_3(0,0,0));
auto b = m.add_vertex(K::Point_3(0,0,0));
auto c = m.add_vertex(K::Point_3(0,0,0));
m.add_face(a,b,c);
Mesh::Halfedge_range range = m.halfedges();
for(Mesh::Halfedge_index hei : range)
{
// ??? <<--
std::cout << hei << std::endl;
}
return 0;
}
Thanks
I think the suggested way to do this is to use the 3d polyhedral surface package instead. The Nef 3 documentation describes the conversion between Polyhedron_3 and Nef_3. The only difference between the 3d polyhedral surface package and the surface mesh package is that, it is pointer based rather than index based.
I am new to managed code and i need to pass array of pointers to different structures to windows form using C++/CLI , but it didn`t work !
My problem is in the managed array, how can i correctly access its elements .
The code sequence :
array<void*> ^ ptr;//here ptr value is undefined , type array<void*> ^
ptr = gcnew array<void*> (2);// length 0x2 , 0x0 and 0x1 values are undefined of type void
class1::struct1 structObj1;
class2::struct2 structObj2;
ptr[0] = &structObj1;// value is empty of type void!!
ptr[1] = &structObj2;//value is empty of type void!!
When i watched ptr , i found the above comments.
Notice that repeating code but using unmanaged array works probably
void* ptr[2];//here ptr value is undefined , type void*[]
class1::struct1 structObj1;
class2::struct2 structObj2;
ptr[0] = &structObj1;// value is address1 of type void*
ptr[1] = &structObj2;//value is address2 of type void*
Can anyone see where is the problem??
Do I need to use unmanaged array then convert to managed? If yes, how can I do it ??
Passing unmanaged pointers in a managed array may be valid C++/CLI, but it's definitely not the ideal way to do things. Do consider creating a custom managed class (ref class in C++/CLI) to hold the structures, instead of passing around pointers.
For this, I'm assuming that struct1 and struct2 are unmanged structs. This answer only applies if that is the case.
Your existing code works for me. Here's my version, with some debugging added in.
public struct struct1 { int foo; };
public struct struct2 { float bar; };
int main(array<System::String ^> ^args)
{
array<void*> ^ ptr;
ptr = gcnew array<void*> (2);
for(int i = 0; i < ptr->Length; i++)
Debug::WriteLine("ptr[{0}] = {1:X8}", i, reinterpret_cast<int>(ptr[i]));
struct1 structObj1;
struct2 structObj2;
ptr[0] = &structObj1;
ptr[1] = &structObj2;
for(int i = 0; i < ptr->Length; i++)
Debug::WriteLine("ptr[{0}] = {1:X8}", i, reinterpret_cast<int>(ptr[i]));
struct1* pointerToStructObj1 = reinterpret_cast<struct1*>(ptr[0]);
structObj1.foo = 4;
Debug::WriteLine("pointerToStructObj1->foo = {0}", pointerToStructObj1->foo);
}
Output:
ptr[0] = 00000000
ptr[1] = 00000000
ptr[0] = 0013F390
ptr[1] = 0013F394
pointerToStructObj1->foo = 4
Edit
To use Debug::WriteLine, add using namespace System::Diagnostics.
The debugger doesn't know how to display the contents of a void*, so it just displays blank. It does display a null pointer differently, though: null shows up as <undefined value>, non-null shows up as just blank.
My philosophy on C++/CLI is: If you're going to write managed code, write managed code. Consider replacing your vector with a managed List. If you still need unmanaged objects, I strongly urge you to consider writing a managed class with properly typed pointers, rather than a void* array.
To implement such a class, create whatever fields you need, just be sure that they're pointers, not direct. (vector<foo>* instead of vector<foo>.) Create the objects with new in the constructor, and delete them in the destructor (which is called on Dispose) & finalizer.