Transfer data from c++ to c#

Hi guys,

Why is the data not output from c++ to c# codes?
Could anyone please help me?
Here CreateFromNativePointer always returns null. The brep data on c++ side is read from a file.

The simplified codes are:

on c# side:

UnsafeNativeMethods.createFlange(const_ptr_brep, out on_brep_ptr);
Brep brep_out = (Brep)Rhino.Runtime.Interop.CreateFromNativePointer(on_brep_ptr);

on c++ side:

extern "C" ExportFunc void createFlange(ON_Brep *input_brep_ptr, ON_Brep **brep_out_ptr)
{
... // read from file and is valid
	if (input_brep_ptr->IsValid())
	{
		*brep_out_ptr = input_brep_ptr->Duplicate();
		return true;
	}
...
}

Are you sure you get a valid pointer out of your createFlange into C# on_brep_ptr is it different from IntPtr.Zero?

the whole c++ code is here (from Dale Fugier). Besides, I have printed the brep address on the c++ side and the address on c# side:

000001EA1A97C8D0 (address string on c++ side)
0x000001ea1a97c8d0 (c# side)

I think, it is the same. I have check the file, there is a model, a relative complex solid model in the file I want to open.

Any idea, what I have done wrong?
Thank you very much.

Regards
John

extern "C" ExportFunc void createFlange(ON_Brep *brep_ptr, ON_Brep **modified_brep_ptr)
{

	const char* c_ptr = "C:\\customer parts\\sheet metal\\Piece test.3dm";
    ONX_Model model;

    if (model.Read(c_ptr))
    {
        ONX_ModelComponentIterator it(model, ON_ModelComponent::Type::ModelGeometry);
        const ON_ModelComponent* model_component = nullptr;
        for (model_component = it.FirstComponent(); nullptr != model_component; model_component = it.NextComponent())
        {
            const ON_ModelGeometryComponent* model_geometry = ON_ModelGeometryComponent::Cast(model_component);
            if (nullptr != model_geometry)
            {
                // Test for Brep object
                const ON_Brep* brep_ptr = ON_Brep::Cast(model_geometry->Geometry(nullptr));
                if (nullptr != brep_ptr)
                {
                    // TODO: do something with the Brep...
                    if (brep_ptr->IsValid())
                    {
                        *modified_brep_ptr = brep_ptr->Duplicate();
                        {
                            std::ostringstream oss;
                            oss << std::hex << *modified_brep_ptr;
                            std::string pointerStr = oss.str();
                            // Open a file in text write mode
                            std::ofstream outFile("c:\\tmp\\pointer_address.txt");
                            // Write the pointer address to the file
                            outFile << pointerStr;
                            // Close the file
                            outFile.close();
                        }
                        return;
                    }
                }
            }
        }
    }
}

Hey, I’ll let @dale further talk about what should work and what not, but from the code snippet you provide here at least one problem is shadowing of the first argument. You have brep_ptr in the argument list for your createFlange method, but then later on you introduce another variable called brep_ptr.

Anyway, @dale probably has a better view on what you’re trying to do here.

Hi Nathan,

The input brep_ptr is ok, I used it as input data, but I need to modified the brep to create another brep, so I add another brep as output pointer, I ignore the first brep now as it works fine. I have used it before. Now I read a brep (solidmodel) from a file and assume it is the output brep. I want to test the basic function to see whether my idea is ok or not. The brep I want to return is a complex model, a solid model.

Regards
John

I would rewrite this to return an ON_Brep* instead of trying to use a pointer to a pointer as an argument. Also as Nathan pointed out it doesn’t seem like the brep_ptr parameter is used at all.

extern "C" ExportFunc ON_Brep* createFlange()
{
  const char* c_ptr = "C:\\customer parts\\sheet metal\\Piece test.3dm";
  ONX_Model model;

  if (!model.Read(c_ptr))
    return nullptr;

  ONX_ModelComponentIterator it(model, ON_ModelComponent::Type::ModelGeometry);
  const ON_ModelComponent* model_component = nullptr;
  for (model_component = it.FirstComponent(); nullptr != model_component; model_component = it.NextComponent())
  {
    const ON_ModelGeometryComponent* model_geometry = ON_ModelGeometryComponent::Cast(model_component);
    if (nullptr != model_geometry)
    {
      // Test for Brep object
      const ON_Brep* brep_ptr = ON_Brep::Cast(model_geometry->Geometry(nullptr));
      if (nullptr != brep_ptr)
      {
        // TODO: do something with the Brep...
        if (brep_ptr->IsValid())
        {
          ON_Brep* modified_brep_ptr = brep_ptr->Duplicate();
          {
            std::ostringstream oss;
            oss << std::hex << *modified_brep_ptr;
            std::string pointerStr = oss.str();
            // Open a file in text write mode
            std::ofstream outFile("c:\\tmp\\pointer_address.txt");
            // Write the pointer address to the file
            outFile << pointerStr;
            // Close the file
            outFile.close();
          }
          return modified_brep;
        }
      }
    }
  }
  return nullptr;
}

Then your C# code would look like

IntPtr brep_ptr = UnsafeNativeMethods.createFlange();
Brep brep_out = Rhino.Runtime.Interop.CreateFromNativePointer(brep_ptr) as Brep;

Hi Steve Baer,

I have tested and your approach doesn’t work either. The brep I got from c# side is null.

I can’t attach the part. But it is a sheet metal model with some flanges and bends. But it is a solid model.

Regards
John

Are you able to step through your C++ code in the debugger and see it return a pointer to the brep?

I can’t debug the c++ codes, but I do add line like “if (brep_ptr->IsValid())”, this should be enough, right?

Regards
John

Hi Steve Baer,

Do you have a sample code which returns a solid from c++ side to c# side?

Regards
John

I think the first step is to get you to be able to debug. There are ways that this function can return null. If your project is a C++ project, set the Visual Studio debugger to mixed. If your project is a C# project, enable native code debugging in the project settings.

All of RhinoCommon is written this way. Here’s an example C++ file that is used by RhinoCommon

I can send you the solution and you can try on your side. It is just a simple proto type that I want to test the basic functions I need.

Regards
John

Have you been able to set a breakpoint in the C++ code and hit that breakpoint in the debugger?

Hey @smartunfold,

This sample is worth browsing.

– Dale

Hi Dale Fugier,

Thank you for your reply.

I have checked all the functions in your project before. It helps me a lot when I did my last project to implement (or integrate ) our product into the grasshopper. I have checked it again today, I didn’t find any sample showing that a brep is returned from c++ side to c# side. If I pass a brep from c# side to c++ side, it works fine. But I doubt that a brep data can be returned from the c++ side to c# side. The codes I have shown here is very simple and straight forward, it is easy to do the test in grasshopper component. It simply doesn’t work.

Hope your guys can double check again.

Regards
John

@smartunfold - there is this:

MOOSECORELIB_C_FUNCTION ON_Brep* MooseFunction3()
{
  const double d = 10.0;
  ON_Circle circle(ON_Plane::World_xy, d);
  ON_Cylinder cylinder(circle, d);
  ON_Brep* brep = ON_BrepCylinder(cylinder, true, true);
  return brep;
}

///
/// <summary>
/// Creates a solid cylinder
/// </summary>
public static Brep ExampleFunction3()
{
  var ptr = UnsafeNativeMethods.MooseFunction3();
  if (ptr == IntPtr.Zero)
    return null;

  var geometry = Interop.CreateFromNativePointer(ptr);
  return geometry as Brep;
}

– Dale

I just add the following codes for creating the cylinder brep to my project, it doesn’t work.

I notice that in the file “MooseNetCommand.cs”, the calling function is commented out.
Anyway, I will try to use your project to test again.

Thank you.
Regards
John

Hi Dale Fugier,

Just use your codes, it works fine. I can see the cylinder created. However, when I try to add my codes to your project, I can’t link, I got the following error, do you have any idea?

Thank you.
Regards
John

opennurbs_public_staticlib.lib(opennurbs_subd_copy.obj) : error LNK2038: mismatch detected for ‘_ITERATOR_DEBUG_LEVEL’: value ‘2’ doesn’t match value ‘0’ in MooseCoreLib.obj
1>opennurbs_public_staticlib.lib(opennurbs_subd_copy.obj) : error LNK2038: mismatch detected for ‘RuntimeLibrary’: value ‘MDd_DynamicDebug’ doesn’t match value ‘MD_DynamicRelease’ in MooseCoreLib.obj
1>opennurbs_public_staticlib.lib(opennurbs_subd_ref.obj) : error LNK2038: mismatch detected for ‘_ITERATOR_DEBUG_LEVEL’: value ‘2’ doesn’t match value ‘0’ in MooseCoreLib.obj

Hi @smartunfold,

Don’t try linking your project with the Moose. Just copy/paste the relevant Moose code into your project…

– Dale