Common Language Runtime support¶
Если есть желание использовать одновременно управляемый и неуправляемый код в реализации и при этом не собирать полностью весь проект с опцией /clr,
необходимо в настройках нужного cpp файла включить опцию /clr и отключить несовместимые с ней опции - /RTC1, /Gm, /EHsc, /Yu, /ZI.
Для примера рассмотрим кусочек кода, который кодирует строку с помощью .NET объекта Encoder.
1. Создадим Win32 Concole Application проект (clr_test.vcproj).
2. Редактируем свойста clr_test.cpp согластно описанию рассмотренному выше.
3. Напишем реализацию кодировщика с помощью функции .NET.
3.1 Подключаем необходимые заголовочники и нэймспэйсы.
#include "stdafx.h"
#include
#include
#using <mscorlib.dll>
using namespace System;
3.2 Прагма managed заставляет генерировать компилятор управляемый код
#pragma managed
3.3 Реализация кодирования строки в Base64 строку.
array<unsigned char>^ GetData(const char* pData, size_t count)
{
array<unsigned char>^ myArray = gcnew array<unsigned char>(count);
for (size_t i = 0; i < count; ++i)
myArray[i] = pData[i];
return myArray;
}
String^ Base64Encode(const std::string& encodeStr, int strLen)
{
array<unsigned char>^ binaryData = GetData(encodeStr.c_str(), strLen);
return Convert::ToBase64String(binaryData);
}
std::string EncodeData(const std::string& encodeStr) {
String^ result = Base64Encode(encodeStr, encodeStr.length());
IntPtr obj = Marshal::StringToHGlobalAnsi(result);
char* res = (char*)(void*)obj;
std::string data(res);
Marshal::FreeHGlobal(obj);
return data;
}
3.4 Прагма unmanaged заставляет генерировать компилятор неуправляемый код
#pragma unmanaged
3.5 Используем функции реализованные в секции неуправляемого кода
int main(int argc, _TCHAR* argv[])
{
std::string str = "Hello world!";
std::cout << "Begin: " << str << "\n";
str = EncodeData(str);
std::cout << "Encode: " << str << "\n";
return 0;
}
- Окошко консольной программы.
{{Image("clr_view1.JPG","nolink")}}
5. Теперь скомпилируем простой пример с опцией компилятора /FAs (C/C -> Output Files-> Assembler output) - Assembly with source code и посмотрим что получилось.
Пример:
static int var;
void test2();
#pragma unmanaged
void test1()
{
var = 1;
test2();
} #pragma managed
void test2()
{
var = 1;
test1();
}
Результат:
.bss
.local _var,4
.text
.global ?test2@@$$FYAXXZ ; test2
?test2@@$$FYAXXZ: ; test2
ldc.i.1 1 ; i32 0x1
stsfld _var
call ?test1@@$$FYAXXZ
ret
.end ?test2@@$$FYAXXZ ; test2
_TEXT ENDS
PUBLIC +mep@?test2@@$$FYAXXZ
PUBLIC ?test2@@YAXXZ ; test2
+
data SEGMENT
+mep@?test2@@$$FYAXXZ TOKEN 0A00000C
data ENDS
+
_TEXT SEGMENT
?test2@@YAXXZ PROC ; test2, COMDAT
jmp DWORD PTR +mep@?test2@@$$FYAXXZ
+
?test2@@YAXXZ ENDP ; test2
_TEXT ENDS
PUBLIC ?test1@@YAXXZ ; test1
_TEXT SEGMENT
?test1@@YAXXZ PROC ; test1
push ebp
mov ebp, esp
mov DWORD PTR _var, 1
call ?test2@@YAXXZ ; test2
pop ebp
ret 0
?test1@@YAXXZ ENDP ; test1
_TEXT ENDS
END
Можно увидеть, что в одном модуле у нас нормально живут MSIL и ассемблер. В обоих случаях вызов функций производится через специальные заглушки. Обращение к переменной происходит напрямую в обоих случаях, с той лишь разницей, что каждая функция делает это по-своему.