Programming‎ > ‎

C++/CLI

C++/CLI Programming Tips

Here are C++/CLI programming tips. Microsoft created a very powerfulC++/CLI for .NET so that you can mix native and managed in the same code.Using this language you can port your C++ libraries into .NET usable librariesvery quickly.

Update: 5/26/2017

Index


How can I write an extension method in C++/CLI?

In C# you can create extension methods. How can I do that in C++/CLI?Here is the answer from stckoverflow: https://stackoverflow.com/questions/6012578/how-can-i-create-net-extension-methods-by-c-cli

  
  using namespace System::Runtime::CompilerServices;  
  ...  
  [ExtensionAttribute]  
  public ref class MyExtensions  
  {    
    public:      
	[ExtensionAttribute]      
	static bool Compare(A% a, A% b);      
	...  
  };
  
Note in C# class is made to be static. Not in C++/CLI.

Top


How can I debug native code as well as C++/CLI?

Do the following:

 
  1. C# side. 
     Properties->Build->Allow unsafe code and Property->Debug->Enable unmanaged code 
  2. C++/CLI side.  Properties->Debugging->Debugger Type->Mixed.
  

Top


How can I convert managed 2d array into C 2d array?

I needed to pass managed 2d array into C routine which takes C style 2d array.Here is how:

    
  int ** Convert(array^ a2d)    
  {      
	int Jmax = a2d->GetLength(0);      
	int Imax = a2d->GetLength(1);      
	int **C = new int*[Jmax];      
	for (int j = 0; j < Jmax; ++j)      
	{        
	  C[j] = new int[Imax];      
	}      
	pin_ptr p2d = &a2d[0, 0];      
	for (int j = 0; j < Jmax; ++j)      
	{        
	  for (int i = 0; i < Imax; ++i)        
	  {          
	    C[j][i] = *(p2d + j * 4 + i);        
	  }      
	}      
	return C;    
  }
  

Top


How can I convert String^ to std::string?

The latest conversion (VS2015) between clr and c++ is https://msdn.microsoft.com/en-us/library/bb384865.aspx.

  
  using <msclr\marshal_cppstd.h>  
  std::string converted = marshal_as<std::string>(managed);
  // older version:  
  using < msclr\marshal.h >  
  msclr::interop::marshal_context^ context = gcnew msclr::interop::marshal_context();  
  std::string fileName = std::string(context->marshal_as<const char *>(clrFileile));  
  // old way  
  IntPtr p = Marshal::StringToHGlobalAnsi(clrFile);  
  std::string fileName = std::string(static_cast<char *>(p.ToPointer()));
  

Top


How can I do Dispose under C++/CLI?

In C#, you write Dispose() for deterministic cleanup. Under C++/CLI, destructor is the one implements Dispose() and a finalizer implements Finalize()

:
 
  ref class A 
  { 
    public:    
	~A() 
	{ 
	  // destructor.  free managed and unmanaged resources. 
	  IDisposable.Dispose()         
	}    
	
	!A() 
	{ 
	  // finalizer.   free only unmanaged resurces.  
	  Object.Finalize()        
	} 
  };
  You do   
  A a = gcnew A();   
  ...   
  delete a;
  

Top


How can I write C# equivalent of ref and out for output parameter?

In C# you can use two ways of getting output from a function call:refand out. They differ very subtle:

   
  void foo1(ref int [] a);   
  void foo2(out int [] a);
  // where both can have modifying constructs inside the foo like
  a = new int[5] { 1, 2, 3, 4, 5};
  // However, the usage is different:
  int [] b = null;   
  foo1(ref b);
  // whereas
  int [] c;   
  foo2(out c);
  // In order to do this for ref in C++/CLI, you must do
  void foo1(array<int>^% a);
  //which is trivial.  For the out version, you have to add one more line:
  using namespace System::Runtime::InteropServices; // this is needed to compile   
  ...   
  void foo2([Out] array<int>^% a); 
  // [Out] can be [OutAttribute]
  

Top


How can I write a event handler using a Form member function?

In C#, adding an event handler for the Form application is easy:

  
  this.button1.Click += new EventHandler(button1Click);
  
In C++/CLI, you have to be more explicit:
  
  this->button1->Click += gcnew System::EventHandler(this, &Form1::button1Click);
  
If you don't use (this, &method), then the method must be a static function.

Top


How can I modify a control when an asynchronous callback is done?

The issue is related to multithread problem. Usually the callback function is called on a different thread than the UI thread. Thus If you try to changethe control inside the Form, you get the exception thrown, saying that youcannot call from a differnt thread (needs Marshal). The way to handle is to write a delegateand Invoke it.

Here is the case of a simpleWebservice returning a string, using an asynchronous call.

  
  private:    
  System::AsyncCallback^ myCallback; // declare callback    
  localhost::Service1^ proxy; // web service  public:    
  Form1(void)    
  {      
    InitializeComponent();      
	//      
	// if I put the code in InitializeComponent(), then it produces error      
	this->myCallback = gcnew AsyncCallback(this, &Form1::OnComplete);      
	//       
	// proxy part (automatically generated when you add web service ref)      
	//       
	this->proxy = (gcnew localhost::Service1());      
	this->proxy->Credentials = nullptr;      
	this->proxy->Url = L"http://localhost/WebServiceSimple/Service1.asmx";      
	this->proxy->UseDefaultCredentials = false;    
  }     
  System::void button1_Click(System::Object^  sender, System::EventArgs^  e)     
  {      
    this->proxy->BeginHelloWorld(myCallback, nullptr); // asynchronous call    
  }    
  // define delegate    
  delegate void SetTextDelegate(String^ msg);    
  // here is what I want to do    
  void setText2(String^ msg)    
  {      
    this->textBox2->Text = msg;    
  }    
  void OnComplete(System::IAsyncResult^ ar)    
  {      
    AsyncResult^ ares = dynamic_cast(ar);      
	int val = Convert::ToInt32(ar->AsyncState);      
	String ^msg = this->proxy->EndHelloWorld(ar); 
	// finish handling      
	if (this->InvokeRequired == false) 
	// in the same thread      
	{        
	  this->textBox2->Text = msg;      
	}      
	else // different thread      
	{        
	  // set delegate        
	  SetTextDelegate^ del = gcnew SetTextDelegate(this, &testWebServiceSimpleCpp::Form1::setText2);	
	  // Invoke (synchronous call)  
	  ... 
	  // you could do BeginInvoke()        
	  this->Invoke(del, msg);      
	}    
  }
  

Top


How can I create a Bitmap object from byte array?

I needed to create a 8bit Bitmap object from byte array. The palette must be set. Here is how. Note that IntPtr has no operator foradding int.


  Bitmap^ getBitmapFromBytes(BYTE *ptr, int width, int height)
  { 
    Bitmap^ bm = gcnew Bitmap(width, height, Imaging::PixelFormat::Format8bppIndexed); 
	Imaging::BitmapData^ bmd = bm->
	LockBits(System::Drawing::Rectangle(0,0,width,height), 
	Imaging::ImageLockMode::WriteOnly, bm->PixelFormat); 
	Int64 head = bmd->Scan0.ToInt64();  
	// there is no operator for adding IntPtr + 
	int array^ src = gcnew array(width); 
	for (int j=0; j < height; ++j) 
	{   
	  IntPtr rowHead = IntPtr(head + j*bmd->Stride);   
	  // this is really stupid   
	  interior_ptr pBegin = &(src[0]);   
	  interior_ptr pEnd = pBegin + width;   
	  BYTE *sPtr = ptr + j*width;   
	  while (pBegin < pEnd)     
	    *pBegin++ = *sPtr++;   
	  // Marshal only takes managed array src to IntPtr   
	  Marshal::Copy(src, 0, rowHead, width); 
	} 
	bm->UnlockBits(bmd); 
	Imaging::ColorPalette^ pal = bm->Palette; 
	for (int i=0; i < pal->Entries->Length; ++i)   
	  pal->Entries[i] = Color::FromArgb(i, i, i); 
	bm->Palette = pal; return bm;
  } 
  

Top


Easy conversion between managed and unmanaged string etc.

It used to be very painful to convert between managed and unmanaged object. Under VS2008, it isnow very easy using marshal_as template class. For example, conversion between String^ and std::string is written as

  
  #include <msclr\marshal_cppstd.h>  
  ...  
  using namespace msclr::interop;  
  ...  
  String^ clrMsg = "Hello, World";  
  std::string stdmsg = marshal_as<std::string>(clrMsg);
  

There are other conversions available, see VC\include\msclr\marshal.h, marshal_atl.h, marshal_windows.h for more information

Top


Home

Updated 10/14/2009