В чем разница между pInvoke и COM Interop? - PullRequest
16 голосов
/ 29 июня 2010

Допустим, я обращаюсь к сторонней библиотеке, для которой в документации указано, что я могу использовать pInvoke или создать библиотеку взаимодействия и использовать COM.В чем разница между этими двумя методами, и почему я могу выбрать один из других?

Ответы [ 3 ]

13 голосов
/ 29 июня 2010

P / Invoke используется для вызова API обычного C (как и большинство API Win32). COM-взаимодействие используется для вызова COM-объектов.

Вы можете создать оболочку COM C ++ вокруг C API, а затем использовать COM-взаимодействие для вызова оболочки, если число вызовов API относительно велико (и вы можете использовать оболочку COM для инкапсуляции их всего в один или два вызова) , Это связано с тем, что управляемое взаимодействие может быть относительно дорогим и хорошо минимизировать количество переходов. Хотя на самом деле я бы сказал, что использование C ++ / CLI для создания оболочки, вероятно, было бы немного более дружественным для C # (например, SlimDX , который является оболочкой C ++ / CLI вокруг COM API (DirectX)).

Сказав, что, если у вас нет конкретной проблемы с производительностью, я бы просто использовал любой более естественный метод для API, который вы пытаетесь вызвать: если это C API (как Win32 API), тогда используйте P / Invoke. Если он основан на COM, используйте COM-взаимодействие.

2 голосов
/ 14 июля 2015

PInvoke использует механизм динамической компоновки для включения внешнего кода в исполняемый процесс.Библиотеки динамической компоновки (DLL) должны иметь ту же целевую архитектуру, что и вызывающее приложение, поэтому нет возможности выполнять перекрестные вызовы с 64-разрядных на 32-разрядные или наоборот.Вместо этого DLL отображается в адресном пространстве вызывающего и выполняется в процессе.

COM, DCOM, COM + и ActiveX основаны на межпроцессных коммуникационных библиотеках, но иногда могут переходить в простую загрузку DLL.Связанные объекты COM связаны, но не идентичны объектам CORBA, но в то время как CORBA разработала свой собственный локатор объектов, реализация COM все еще слабо основана на библиотеках RPC и XDR Sun Microsystems с расширениями для объектно-ориентированных функций COM.На COM-объекты ссылаются не DLL, а GUID, который используется для поиска класса объекта и запроса его интерфейсов.Код объекта обычно выполняется в отдельном процессе и, возможно, на отдельном сервере.

0 голосов
/ 16 января 2019

Функциональная совместимость позволяет вам сохранять и использовать существующие вложения в неуправляемый код.Код, который выполняется под управлением общеязыковой среды выполнения (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;  
}
...