Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

680
Views
Pasar un vector/matriz de C++ no administrado a C#

Quiero pasar alrededor de 100 - 10,000 Puntos de un C++ no administrado a C#.

El lado de C++ se ve así:

 __declspec(dllexport) void detect_targets( char * , int , /* More arguments */ ) { std::vector<double> id_x_y_z; // Now what's the best way to pass this vector to C# }

Ahora mi lado C# se ve así:

 using System; using System.Runtime.InteropServices; class HelloCpp { [DllImport("detector.dll")] public static unsafe extern void detect_targets( string fn , /* More arguments */ ); static void Main() { detect_targets("test.png" , /* More arguments */ ); } }

¿Cómo necesito modificar mi código para pasar el std::vector de C++ no administrado con todo su contenido a C#?

over 4 years ago · Santiago Trujillo
3 answers
Answer question

0

Siempre que el código administrado no cambie el tamaño del vector, puede acceder al búfer y pasarlo como un puntero con vector.data() (para C++0x) o &vector[0] . Esto da como resultado un sistema de copia cero.

Ejemplo de API de C++:

 #define EXPORT extern "C" __declspec(dllexport) typedef intptr_t ItemListHandle; EXPORT bool GenerateItems(ItemListHandle* hItems, double** itemsFound, int* itemCount) { auto items = new std::vector<double>(); for (int i = 0; i < 500; i++) { items->push_back((double)i); } *hItems = reinterpret_cast<ItemListHandle>(items); *itemsFound = items->data(); *itemCount = items->size(); return true; } EXPORT bool ReleaseItems(ItemListHandle hItems) { auto items = reinterpret_cast<std::vector<double>*>(hItems); delete items; return true; }

Llamador:

 static unsafe void Main() { double* items; int itemsCount; using (GenerateItemsWrapper(out items, out itemsCount)) { double sum = 0; for (int i = 0; i < itemsCount; i++) { sum += items[i]; } Console.WriteLine("Average is: {0}", sum / itemsCount); } Console.ReadLine(); } #region wrapper [DllImport("Win32Project1", ExactSpelling = true, CallingConvention = CallingConvention.Cdecl)] static unsafe extern bool GenerateItems(out ItemsSafeHandle itemsHandle, out double* items, out int itemCount); [DllImport("Win32Project1", ExactSpelling = true, CallingConvention = CallingConvention.Cdecl)] static unsafe extern bool ReleaseItems(IntPtr itemsHandle); static unsafe ItemsSafeHandle GenerateItemsWrapper(out double* items, out int itemsCount) { ItemsSafeHandle itemsHandle; if (!GenerateItems(out itemsHandle, out items, out itemsCount)) { throw new InvalidOperationException(); } return itemsHandle; } class ItemsSafeHandle : SafeHandleZeroOrMinusOneIsInvalid { public ItemsSafeHandle() : base(true) { } protected override bool ReleaseHandle() { return ReleaseItems(handle); } } #endregion
over 4 years ago · Santiago Trujillo Report

0

Implementé esto usando el contenedor C++ CLI. C++ CLI es uno de los tres enfoques posibles para la interoperabilidad de C++ C#. Los otros dos enfoques son P/Invoke y COM. (He visto a algunas buenas personas recomendar el uso de C++ CLI sobre los otros enfoques)

Para ordenar la información del código nativo al código administrado, primero debe envolver el código nativo dentro de una clase administrada de la CLI de C++. Cree un nuevo proyecto para que contenga código nativo y su contenedor C++ CLI. Asegúrese de habilitar el modificador del compilador /clr para este proyecto. Compile este proyecto en una dll. Para usar esta biblioteca, simplemente agregue su referencia dentro de C# y realice llamadas contra ella. Puede hacer esto si ambos proyectos están en la misma solución.

Aquí están mis archivos fuente para un programa simple para ordenar un std::vector<double> desde el código nativo al código administrado de C#.

1) Proyecto EntityLib (C++ CLI dll) (Código nativo con contenedor)

Archivo NativeEntity.h

 #pragma once #include <vector> class NativeEntity { private: std::vector<double> myVec; public: NativeEntity(); std::vector<double> GetVec() { return myVec; } };

Archivo NativeEntity.cpp

 #include "stdafx.h" #include "NativeEntity.h" NativeEntity::NativeEntity() { myVec = { 33.654, 44.654, 55.654 , 121.54, 1234.453}; // Populate vector your way }

Archivo ManagedEntity.h (clase contenedora)

 #pragma once #include "NativeEntity.h" #include <vector> namespace EntityLibrary { using namespace System; public ref class ManagedEntity { public: ManagedEntity(); ~ManagedEntity(); array<double> ^GetVec(); private: NativeEntity* nativeObj; // Our native object is thus being wrapped }; }

Archivo ManagedEntity.cpp

 #include "stdafx.h" #include "ManagedEntity.h" using namespace EntityLibrary; using namespace System; ManagedEntity::ManagedEntity() { nativeObj = new NativeEntity(); } ManagedEntity::~ManagedEntity() { delete nativeObj; } array<double>^ ManagedEntity::GetVec() { std::vector<double> tempVec = nativeObj->GetVec(); const int SIZE = tempVec.size(); array<double> ^tempArr = gcnew array<double> (SIZE); for (int i = 0; i < SIZE; i++) { tempArr[i] = tempVec[i]; } return tempArr; }

2) Proyecto SimpleClient (C# exe)

 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using EntityLibrary; namespace SimpleClient { class Program { static void Main(string[] args) { var entity = new ManagedEntity(); for (int i = 0; i < entity.GetVec().Length; i++ ) Console.WriteLine(entity.GetVec()[i]); } } }
over 4 years ago · Santiago Trujillo Report

0

Podría pensar en más de una opción, pero todas incluyen copiar los datos de la matriz de todos modos. Con [out] parámetros podrías probar:

código C++

 __declspec(dllexport) void __stdcall detect_targets(wchar_t * fn, double **data, long* len) { std::vector<double> id_x_y_z = { 1, 2, 3 }; *len = id_x_y_z.size(); auto size = (*len)*sizeof(double); *data = static_cast<double*>(CoTaskMemAlloc(size)); memcpy(*data, id_x_y_z.data(), size); }

código C#

 [DllImport("detector.dll")] public static extern void detect_targets( string fn, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2)] out double[] points, out int count); static void Main() { int len; double[] points; detect_targets("test.png", out points, out len); }
over 4 years ago · Santiago Trujillo Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!