Link to home
Start Free TrialLog in
Avatar of perrytaylor
perrytaylor

asked on

Calling a c++ dll from a C# app

I am missing something simple here.  I have created a roots routine from the Numerical Recipes book in a c++ class and saved it as a .dll .   That builds and I think is good.  What I am am failing to figure out is how to call it in my C# application.  It appears as though the methods in C++ are set to private but they are most definitely set to public.  I have referenced the dll file in my C# project and have used an including statement at the top and can see the namespace and the class but not the method.  The details of the C++ code have been left out for copyright /respect reasons and I don't think they are the cause of the problem here.
C++ code:
 
#include "nr3.h"
 
using namespace System;
 
namespace Numerical_Methods 
{
 
	public ref class Roots
	{
		public: 
			
			static void laguer(VecComplex_I &a, Complex &x, Int &its)
		{
			laguer code.
 
		}
 
 
 
	
			static void zroots(VecComplex_I &a, VecComplex_O &roots, const Bool &polish)
		{
			polish code for laguere.
		}
 
 
	};
}

Open in new window

Avatar of CuteBug
CuteBug
Flag of India image

You need to use System.Runtime.InteropServices to call a C++ dll method from C#

http://msdn.microsoft.com/en-us/magazine/cc164123.aspx
http://www.ddj.com/cpp/184406285
Avatar of perrytaylor
perrytaylor

ASKER

Even if I wrote the C++ dll in .net?
If you use C++ .net you don't need InteropServices.
Can you try to add a method that has all the paremeters of .NET types?
How VecComplex_I, VecComplex_O and Complex are defined?
Try also:

static void laguer(VecComplex_I^ a, Complex^ x, Int its)
VecComplex_I, VecComplex_O and Complex are all defined in nr3.h which is publicly available and I have included it below.  

static void laguer(VecComplex_I^ a, Complex^ x, Int its) gave all sorts of errors.  Like
Error      1      error C3699: '^' : cannot use this indirection on type 'VecComplex_I'
Error      2      error C3699: '^' : cannot use this indirection on type 'Complex'      
Error      3      error C2228: left of '.size' must have class/struct/union
Error      4      error C2679: binary '=' : no operator found which takes a right-hand operand of type 'VecComplex_I' (or there is no acceptable conversion)      
Error      5      error C2665: 'std::abs' : none of the 6 overloads could convert all the argument types      
Error      6      error C2678: binary '*' : no operator found which takes a left-hand operand of type 'Complex *' (or there is no acceptable conversion)      
Error      7      error C2678: binary '*' : no operator found which takes a left-hand operand of type 'Complex *' (or there is no acceptable conversion)      
Error      8      error C2678: binary '*' : no operator found which takes a left-hand operand of type 'Complex *' (or there is no acceptable conversion)      
Error      9      error C2679: binary '-' : no operator found which takes a right-hand operand of type 'Complex' (or there is no acceptable conversion)      
Error      10      error C2679: binary '==' : no operator found which takes a right-hand operand of type 'Complex' (or there is no acceptable conversion)      
Error      11      error C2440: '=' : cannot convert from 'Complex' to 'Complex *'      
Error      12      error C2677: binary '-=' : no global operator found which takes type 'std::complex<double>' (or there is no acceptable conversion)      
Error      13      error C2664: 'Numerical_Methods::Roots::laguer' : cannot convert parameter 1 from 'VecComplex' to 'VecComplex_I *'      
Error      14      error C2664: 'Numerical_Methods::Roots::laguer' : cannot convert parameter 1 from 'VecComplex_I' to 'VecComplex_I *'      


// Numerical_Methods.h
 
#pragma once
#include "nr3.h"
 
using namespace System;
 
namespace Numerical_Methods 
{
 
	public ref class Roots
	{
		public: 
			
			static void laguer(VecComplex_I^ a, Complex^ x, Int &its)
		{
			const Int MR=8, MT=10, MAXIT =MT*MR;
			const Doub EPS=numeric_limits<Doub>::epsilon();
 
			static const Doub frac[MR+1]=
			{0.0,0.5,0.25,0.75,0.13,0.38,0.62,0.88,1.0};
 
			Complex dx,x1,b,d,f,g,h,sq,gp,gm,g2;
			Int m=a.size()-1;
			for (Int iter = 1; iter<=MAXIT; iter++)
			{
				its = iter;
				b=a[m];
				Doub err=abs(b);
				d=f=0.0;
				Doub abx =abs(x);
				for (Int j=m-1;j>=0;j--)
				{
					f=x*f*d;
					d=x*d+b;
					b=x*b+a[j];
					err=abs(b)+abx*err;
				}
				err *=EPS;
				if(abs(b)<=err) return;
				g=d/b;
				g2=g*g;
				h=g2-2.0*f/b;
				sq = sqrt(Doub(m-1)*(Doub(m)*h-g2));
				gp=g+sq;
				gm=g-sq;
				Doub abp =abs(gp);
				Doub abm = abs(gm);
				if(abp<abm) gp=gm;
				dx=MAX(abp,abm)>0 ? Doub(m)/gp : polar(1+abx,Doub(iter));
				x1=x-dx;
				if(x==x1) return;
				if (iter % MT != 0) x=x1;
				else x -= frac[iter/MT]*dx;
			}
			throw("too many iterations in laguer");
 
		}
 
 
 
	
			static void zroots(VecComplex_I a, VecComplex_O roots, const Bool polish)
		{
			const Doub EPS=1.0e14;
			Int i, its;
			Complex x,b,c;
			Int m=a.size()-1;
			VecComplex ad(m+1);
			for (Int j=0;j<=m; j++) ad[j]=a[j];
			for (Int j=m-1;j>=0;j--)
			{
				x=0.0;
				VecComplex ad_v(j+2);
				for(Int jj=0;jj<j+2;jj++) ad_v[jj]=ad[jj];
				laguer(ad_v,x,its);
				if(abs(imag(x)) <= 2.0*EPS*abs(real(x)))
					x=Complex(real(x),0.0);
				roots[j]=x;
				b=ad[j+1];
				for (Int jj=j;jj>=0;jj--)
				{
					c=ad[jj];
					ad[jj]=b;
					b=x*b+c;
				}
			}
			if(polish)
				for (Int j=0;j<m;j++)
					laguer(a,roots[j],its);
			for(Int j=1;j<m;j++)
			{
				x=roots[j];
				for (i=j-1; i>=0;i--)
				{
					if (real(roots[i])<=real(x)) break;
					roots[i+1]=roots[i];
				}
				roots[i+1]=x;
			}
		}
 
 
	};
}

Open in new window

Ok, we might be getting somewhere.  The following code does appear in my C# app.

                  static void test(double in)
                  {
                        double tets = in;
                  }

What could it be about the header file/ custom variables that it doesn't like?
I think that VecComplex_I is not a .net compliant type. You should write a wrapper (.net class) for it
How would I go about writing a wrapper class?
ASKER CERTIFIED SOLUTION
Avatar of alb66
alb66
Flag of Italy image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Just a quick comment, C++ uses a concept called "name-mangling", where it basically "mangles" the hell out of your function names to enable function overloading. In other words, it appends some extra junk on the end of each function's identifier in order to diferentiate them by more than just their name. I believe Managed C++ prevents this, but I may be wrong.

I can't explain every little thing that may be going wrong here, but on top of the name-mangling, your probably may lie in the CLS (Common Language Specification), and whether or not these objects you're handling in C++ are CLS-Compliant. The reason these objects must be "compliant" is because every native C++ type you use in C# must be "mapped out" to a corresponding type in C# (for example, Native C++'s "char" primitive type maps out the a "System.SByte" in VC#).

A third problem may arise from VC# being so strict about having some sort of a passion for hating pointers. Any code block that utilizes pointers in VC# MUST appear within an "unsafe" block, as well as the entire assembly be compiled with the /unsafe switch. This essentially overrides some of the .NET Framework's type-safety checking, allowing for pointers, the useage of the stackalloc keyword, among other things.
I apologize for the long delay.  I decided to go a different route but this is certainly the answer to my question.