C++/CLI Programming TipsHere 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.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.
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;
}
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())); 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;
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]
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. 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);
}
}
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;
}
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 Updated 10/14/2009 |
Programming‎ > ‎