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‎ > ‎