Функциональная совместимость позволяет вам сохранять и использовать существующие вложения в неуправляемый код.Код, который выполняется под управлением общеязыковой среды выполнения (CLR), называется управляемым кодом, а код, который выполняется вне CLR, называется неуправляемым кодом.Компоненты COM, COM +, C ++, ActiveX и Microsoft Win32 API являются примерами неуправляемого кода.
.NET Framework обеспечивает взаимодействие с неуправляемым кодом с помощью служб вызова платформы (P / Invoke), System.Runtime.Пространство имен InteropServices, совместимость C ++ и COM-совместимость (COM-взаимодействие).
PInvoke использует механизм динамического связывания для переноса внешнего кода в исполняемый процесс.Библиотеки динамической компоновки (DLL) должны иметь ту же целевую архитектуру, что и вызывающее приложение, поэтому нет возможности выполнять перекрестные вызовы с 64-разрядных на 32-разрядные или наоборот.Вместо этого DLL отображается в адресное пространство вызывающего и выполняется в процессе.
COM, DCOM, COM + и ActiveX основаны на межпроцессных коммуникационных библиотеках, но иногда переходят в простую загрузку DLL.Связанные объекты COM связаны, но не идентичны объектам CORBA, но в то время как CORBA разработала свой собственный локатор объектов, реализация COM все еще слабо основана на библиотеках RPC и XDR Sun Microsystems с расширениями для объектно-ориентированных функций COM.На COM-объекты ссылаются не DLL, а GUID, который используется для поиска класса объекта и запроса его интерфейсов.Объектный код обычно выполняется в отдельном процессе или может находиться на отдельном сервере.
Для языков .NET, таких как Visual Basic и C #, предписанным методом взаимодействия с нативными компонентами является P / Invoke.Поскольку P / Invoke поддерживается .NET Framework, Visual C ++ также поддерживает его, но Visual C ++ также предоставляет собственную поддержку взаимодействия, которая называется C ++ Interop.Взаимодействие C ++ предпочтительнее P / Invoke, поскольку P / Invoke не является безопасным для типов.В результате об ошибках в основном сообщается во время выполнения, но C ++ Interop также имеет преимущества в производительности по сравнению с P / Invoke.
Маршалинг данных, выполняемый C ++ Interop, является самой простой из возможных форм: параметры просто копируются по всейуправляемая / неуправляемая граница побитовым образом;преобразование не выполняется вообще.Для P / Invoke это верно только в том случае, если все параметры являются простыми, blittable типами.В противном случае P / Invoke выполняет очень надежные шаги для преобразования каждого управляемого параметра в соответствующий собственный тип, и наоборот, если аргументы помечены как «out» или «in, out».
Другими словами,C ++ Interop использует самый быстрый из возможных методов маршалинга данных, тогда как P / Invoke использует самый надежный метод.Это означает, что C ++ Interop (типично для C ++) обеспечивает оптимальную производительность по умолчанию, и программист отвечает за рассмотрение случаев, когда это поведение небезопасно или не подходит.
C ++ Interop требует, чтобы маршалинг данных должен былбыть предоставлены в явном виде, но преимущество заключается в том, что программист может решать, что уместно, учитывая природу данных и то, как они должны использоваться.Кроме того, хотя поведение маршалинга данных P / Invoke может быть изменено до определенной степени, взаимодействие с C ++ позволяет настраивать маршалинг данных на индивидуальной основе.Это невозможно с P / Invoke.
P / Invoke Пример ниже:
using System;
using System.Runtime.InteropServices;
public class Win32 {
[DllImport("user32.dll", CharSet=CharSet.Auto)]
public static extern IntPtr MessageBox(int hWnd, String text,
String caption, uint type);
}
public class HelloWorld {
public static void Main() {
Win32.MessageBox(0, "Hello World", "Platform Invoke Sample", 0);
}
}
Пример взаимодействия с Com (в C ++, использующий код c #)
// ConLoan.cpp : Defines the entry point for the console application.
#include "stdafx.h"
#import "..\LoanLib\LoanLib.tlb" raw_interfaces_only
using namespace LoanLib;
int main(int argc, char* argv[])
{
HRESULT hr = CoInitialize(NULL);
ILoanPtr pILoan(__uuidof(Loan));
if (argc < 5)
{
printf("Usage: ConLoan Balance Rate Term Payment\n");
printf(" Either Balance, Rate, Term, or Payment must be 0\n");
return -1;
}
double openingBalance = atof(argv[1]);
double rate = atof(argv[2])/100.0;
short term = atoi(argv[3]);
double payment = atof(argv[4]);
pILoan->put_OpeningBalance(openingBalance);
pILoan->put_Rate(rate);
pILoan->put_Term(term);
pILoan->put_Payment(payment);
if (openingBalance == 0.00)
pILoan->ComputeOpeningBalance(&openingBalance);
if (rate == 0.00) pILoan->ComputeRate(&rate);
if (term == 0) pILoan->ComputeTerm(&term);
if (payment == 0.00) pILoan->ComputePayment(&payment);
printf("Balance = %.2f\n", openingBalance);
printf("Rate = %.1f%%\n", rate*100);
printf("Term = %.2i\n", term);
printf("Payment = %.2f\n", payment);
VARIANT_BOOL MorePmts;
double Balance = 0.0;
double Principal = 0.0;
double Interest = 0.0;
printf("%4s%10s%12s%10s%12s\n", "Nbr", "Payment", "Principal", "Interest", "Balance");
printf("%4s%10s%12s%10s%12s\n", "---", "-------", "---------",
"--------", "-------");
pILoan->GetFirstPmtDistribution(payment, &Balance, &Principal, &Interest, &MorePmts);
for (short PmtNbr = 1; MorePmts; PmtNbr++)
{
printf("%4i%10.2f%12.2f%10.2f%12.2f\n",
PmtNbr, payment, Principal, Interest, Balance);
pILoan->GetNextPmtDistribution(payment, &Balance, &Principal, &Interest, &MorePmts);
}
CoUninitialize();
return 0;
}