C # Managed and unmanaged mixed programming

Source: Internet
Author: User
Tags hosting

Implementing your more important algorithm in an unmanaged module and then interoperating with the CLR's platform to make the managed code call it so that the program still works, but it is difficult to decompile the unmanaged native code.

The most straightforward way to implement managed and unmanaged programming is to use C + +/CLI

Introduced

Project archiving has always been an enterprise adoption practice, but it turns out that they are right too! For a programmer, this is thousands of men-days of work. Why not develop a small piece of code to re-use that piece of code, project.
Now provides a gradual shift to C # 's new technology: Using managed and unmanaged mixed programming. This is a viable scenario in Top-down issue (from UI to low-level layers) or bottom-up (from low-level to UI) case.
The purpose of this article is to illustrate how to use these two techniques together with two simple examples:
* Call managed code in unmanaged.
* Call unmanaged code in escrow.

Calling managed functions in unmanaged code


This example focuses on calling the use of managed (C #) code implementation classes in unmanaged code (c + +) to implement the "mixed code" DLL through managed code to export the API.

Single unmanaged code

The following is a console program

#include "stdafx.h"#include <iostream>using namespaceStd;#ifdef _UNICODE#define COUT Wcout#define CInt Wcin#endifint _tmain (int argc, tchar* argv[]) {unreferenced_parameter (ARGC); Unreferenced_parameter (argv); SYSTEMTIMESt = {0}; Const tchar* Pszname = _t ("John SMITH");St. wyear =1975;St. Wmonth =8;St. wday =15; CPerson person (pszname, &St) ; cout << pszname << _t ("born") << person. GET_BIRTHDATESTR (). C_STR () << _t (  "Age was") << person. Get_age () << _t ("years-old today.") << Endlcout << _t ("Press ENTER to terminate ..."); Cin. Get ();  #ifdef _DEBUG _CrtDumpMemoryLeaks ();  #endif return 0;}                 

There's nothing special about this code, it's just a normal unmanaged code.

A single managed code

This is a typical assembler implemented using C #

Using System;namespace adr.samples.nativecallingclr.clrassembly{PublicClass Person {Privatestring _name;Private DateTime _birthdate;PublicPerson (String name, DateTime birthDate) {This._name = name;This._birthdate = birthDate; }PublicUINT Age {get {DateTime now = DateTime.Now;int = now. Year- This._birthdate.year; if (this._birthdate.month > now. Month) | | (This._birthdate.month = = Now. Month) && (this._birthdate.day > now. Day)) {--age;} return (uint) age;} public string Birthdatestr { get { return this._birthdate.toshortdatestring ();}} Public DateTime BirthDate { get { return this._birthdate;}      }} 

As you can see, this is a single CLR.

Managed and unmanaged Mixed programming section

This part is the most important, but also the hardest. The VisualStudio environment provides some header files to help developers link these keywords.

#include <vcclr.h>

But that's not the end of it. We also need to be careful about some of the pitfalls involved, especially the delivery of data between the CLR (managed code) and native (unmanaged code) with some keywords.
The following is a header file for a class that outputs a managed section

#pragma once#ifdef Nativedll_exports#Define NATIVEDLL_API __declspec (dllexport)#Else#Define NATIVEDLL_API __declspec (dllimport)#endif#include <string>using namespace Std;#ifdef _unicode typedef wstring tstring;#else typedef string tstring; #endifclass nativedll_api CPerson{ public://initialization cperson (LPCTSTR pszName, const systemtime* birthDate); virtual ~cperson (); //accessors unsigned int get_age () const; tstring get_birthdatestr () CONST; SYSTEMTIME get_birthdate () const; Private://Embedded Wrapper of a instance of a CLR class//goal:completely hide CLR to Pure unmanaged/C + + code void* m_ppersonclr;};        

Emphasize that, as far as possible in the header file to ensure that only unmanaged code, mixed programming in the CPP to achieve, data transfer. For example: You should try to avoid using the functions in Vcclr.h to do mixed programming. This is why a void pointer is defined to wrap a CLR object.
A magical gate, so open ...
As I said, the magic begins with a vcclr.h header file. However, you need to use the CLR encoding language and use some complex types (for example: strings, array, etc):

namespace System;using namespace Runtime::InteropServices;using namespace AdR::Samples::NativeCallingCLR::ClrAssembly;

Of course, you need to declare some of the local assemblers used.
First, let's look at the constructor for this class:

CPerson::CPerson(LPCTSTR pszName, const SYSTEMTIME* birthDate){ DateTime^ dateTime = gcnew DateTime((int)birthDate->wYear, (int)birthDate->wMonth, (int)birthDate->wDay); String^ str = gcnew String(pszName); Person^ person = gcnew Person(str, *dateTime); // Managed type conversion into unmanaged pointer is not // allowed unless we use "gcroot<>" wrapper. gcroot<Person^> *pp = new gcroot<Person^>(person); this->m_pPersonClr = static_cast<void*>(pp);}

The

Allows a pointer to a managed class in unmanaged code, but we don't want to go directly to the user with a hosted API.
So, we use a void pointer to encapsulate the object, and a new problem arises: we are not allowed to point directly to the managed type with an unmanaged pointer. That's why we use the Gcroot<> template class. The
needs to be aware of the need to add a ^ character when pointing to managed code with pointers, which means we use a reference pointer to the managed class. Remember that class objects are in. NET is considered a reference when it is used as a function member. The
also needs to be aware of a. NET of automatic memory allocation keywords: gcnew. This means that we allocate space in a garbage collector-protected environment, not in the process heap. The
sometimes needs to be careful: the process heap and the garbage collector protect the environment completely differently. We will see some encapsulation tasks to do: destructors in classes:

CPerson::~CPerson(){   if (this->m_pPersonClr)   {      // Get the CLR handle wrapper      gcroot<Person^> *pp =  static_cast<gcroot<Person^>*>(this->m_pPersonClr); // Delete the wrapper; this will release the underlying CLR instance delete pp; // Set to null this->m_pPersonClr = 0; }}

We use standard C + + types to convert static_case. Deleting an object frees the potentially encapsulated CLR object, allowing it to enter the garbage collection mechanism.
Reminder: The reason for declaring a destructor is to implement the Idisposeable interface and its own Dispose () method.
Key: Do not forget to call Dispose () in the CPerson instance. Otherwise, it causes a memory leak, just as it cannot be freed in C + + (destructors are not called). The
calls the basic CLR class members very easily, similar to the above.

unsigned int CPerson::get_Age() const{   if (this->m_pPersonClr != 0) { // Get the CLR handle wrapper gcroot<Person^> *pp = static_cast<gcroot<Person^>*>(this->m_pPersonClr); // Get the attribute return ((Person^)*pp)->Age; } return 0;}

However, when we have to return a complex type, it's a little trickier, just like the following class members:

tstring CPerson::get_   Birthdatestr () const{tstring strage; if (this->m_ppersonclr! = 0) { Span class= "Hljs-comment" >//Get the CLR handle wrapper gcroot<person^> *pp = static_ Cast<gcroot<person^>*> (this->m_ppersonclr); //Convert to std::string //Note:  -Marshaling is mandatory //-don't forget to get the string pointer ... strage = (const tchar*) Marshal::stringtohglobalauto (((person^) *pp)->birthdatestr). ToPointer (); } return strage;}            

We cannot directly return an System::String object to an unmanaged String. You must use a few steps:
1. Get the System::String object.
2. Use Marshal::stringtohglobalauto () to get a global handle. We are using the "auto" version here to return a Unicode encoded string. Then convert as much as possible to the ANSI-encoded string;
3. Finally, get a pointer to a handle to a potential containing object.
The above 3 steps to achieve the replacement!
Read the recommended book about C + +/CLI, you will see some other special keywords, such as pin_ptr<> and interna_ptr<> allow you to get pointers hidden objects, read the document can get more details.

Large mix

This is a standard example of how to create a local console program using MFC and Clr!

Conclusion (unmanaged call hosting)

Calling hosting in unmanaged is a complex thing, and this example is very basic and common. In the example, you can see some very complicated considerations. Hopefully you can get more experience in future mixed programming, with more of the other scenarios.

unmanaged calls in Managed


This example shows how to invoke an unmanaged C + + class library in the CLR (C #) and export an API to use unmanaged code with the intermediate medium "mixed code" DLL.

unmanaged C++dll

DLL Export:
1. A C + + class
2. A C-style function
3. A C-style variable
This paragraph describes the object of the declaration, although they are very simple, so that there is no need to comment.
C + + Class

class NATIVEDLL_API CPerson {public:   // Initialization   CPerson(LPCTSTR pszName, SYSTEMTIME birthDate);   // Accessors   unsigned int get_Age();private: TCHAR m_sName[64]; SYSTEMTIME m_birthDate; CPerson();};

The Get_age () function is simple enough to calculate a time period from birth to present.
Exporting C functions

int fnNativeDLL(void);

Exporting C variables

int nNativeDLL;

. NET End

This is not a detailed introduction to this classic case.

Note 1:
. NET class cannot inherit directly from an unmanaged C + + class. Write a managed C + + class embedded inside the C + + entity object.

NOTE 2:
declare a member Cperson_person2; causes a C4368 compilation error to be generated (cannot define ' member ' as a member of a managed type: Mixed types are not supported)
This is why internal use (in C # is considered ' unsafe ')
This is what the technical documentation says:
You cannot embed an unmanaged data member directly into the CLR. However, you can declare a pointer to a localized type, in the constructor, destructor, release the managed class to control its life cycle (see in Visual C + + For more information about destructors and finalizers).
This is the embedded object:

CPerson* _pPerson;

Instead of:

CPerson person;

Special information in the constructor
The public constructor has a system::string String (managed type) and a systemtime struct (Win32 API type, but only numeric: obviously a dataset)
This unmanaged C + + CPerson constructor uses a pointer of type LPCTSTR string that cannot be converted directly to an unmanaged object.
This is the source code for the constructor:

SYSTEMTIME st = { (WORD)birthDate.Year,                  (WORD)birthDate.Month,                  (WORD)birthDate.DayOfWeek,                  (WORD)birthDate.Day,                  (WORD)birthDate.Hour,                  (WORD)birthDate.Minute,                  (WORD)birthDate.Second,                  (WORD)birthDate.Millisecond };// Pin ‘name‘ memory before calling unmanaged codepin_ptr<const TCHAR> psz = PtrToStringChars(name);// Allocate the unmanaged object_pPerson = new CPerson(psz, st);

Note that the PIN_PTR keyword is used here to protect strings that can be used in CRLs.
This is a pointer that can protect the object from pointing inward. It is necessary to pass the address of a managed class to an unmanaged function because the address is not an exception change when unmanaged code is called.

Summary (call unmanaged in escrow)

If we feel that importing an unmanaged in escrow is more common than importing a host in unmanaged, it is quite difficult to write a "intermediate assembly".
You should be sure that you need to migrate all your code, which is unreasonable. Consider re-designing the application. Rewriting managed code can be more cost effective than porting. Moreover, the final application architecture is clear and unambiguous.

C # Managed and unmanaged mixed programming

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.