让我们说我正在访问第三方库,其文档声明我可以使用pInvoke或创建互操作库并使用COM。这两种技术之间有什么区别,为什么我可以选择其中一种?
答案 0 :(得分:13)
P / Invoke用于调用plain-C API(与大多数Win32 API一样)。 COM interop用于调用COM对象。
如果API调用的数量相对较高,您可以围绕C API创建一个C ++ COM包装器,然后使用COM interop来调用您的包装器(并且您可以使用COM包装器将它们封装到一个或两个调用中) 。这是因为托管本机互操作可能相对昂贵,并且最小化转换次数是有益的。虽然实际上我会说使用C ++ / CLI创建包装器可能对C#方面更友好(例如SlimDX,这是围绕COM API的C ++ / CLI包装器(的DirectX))。
话虽如此,除非你有一个特定的性能问题,否则我会使用你试图调用的API更自然的方法:如果它是一个C API(如Win32 API那样)那么使用P /调用。如果它是基于COM的,那么使用COM互操作。
答案 1 :(得分:2)
PInvoke使用动态链接机制将外部代码引入执行进程。动态链接库(DLL)必须与调用应用程序具有相同的目标体系结构,因此无法进行从64位到32位的交叉调用,反之亦然。而是将DLL映射到调用者的地址空间并在进程中执行。
COM,DCOM,COM +和ActiveX都基于进程间通信库,但有时可以转换为简单的DLL加载。 COM链接对象是相关的,但与CORBA对象不完全相同,但是当CORBA进化出自己的对象定位器时,COM实现仍然基于Sun Microsystems RPC和XDR库,它们具有COM面向对象功能的扩展。 COM对象不是由DLL引用,而是由GUID引用,GUID用于查找对象类并查询其接口。目标代码通常在单独的进程中运行,并且可能在单独的服务器上运行。
答案 2 :(得分:-1)
互操作性使您可以保留和利用对非托管代码的现有投资。在公共语言运行库(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实现仍然宽松地基于Sun Microsystems RPC和XDR库,并带有COM面向对象功能的扩展。 COM对象不是由DLL引用的,而是由一个GUID引用的,该GUID用于查找对象类并查询其接口。目标代码通常在单独的进程中运行,或者可以在单独的服务器上。
对于.NET语言(例如Visual Basic和C#),与本机组件进行互操作的规定方法是P / Invoke。因为.NET Framework支持P / Invoke,所以Visual C ++也支持它,但是Visual C ++还提供了自己的互操作性支持,这称为C ++ Interop。 C ++ Interop优于P / Invoke,因为P / Invoke不是类型安全的。因此,错误主要是在运行时报告的,但是C ++ Interop的性能优于P / Invoke。
由C ++ Interop执行的数据封送处理是最简单的形式:将参数以位方式简单地复制到托管/非托管边界上。根本不执行任何转换。对于P / Invoke,仅当所有参数均为简单的可变位类型时,才为真。否则,P / Invoke将执行非常健壮的步骤,将每个托管参数转换为适当的本机类型,如果将参数标记为“ out”或“ in,out”,则反之亦然。
换句话说,C ++ Interop使用最快的数据封送方法,而P / Invoke使用最可靠的方法。这意味着默认情况下,C ++ Interop(以C ++的典型方式)提供最佳性能,并且程序员负责解决这种行为不安全或不适当的情况。
因此,C ++ Interop要求必须明确提供数据封送处理,但是优点是,程序员可以自由地决定什么是适当的(在给定数据的性质以及如何使用的情况下)。此外,尽管可以在一定程度上自定义P / Invoke数据封送的行为,但是C ++ Interop允许在逐个呼叫的基础上自定义数据封送。使用P / Invoke无法做到这一点。
下面的P /调用示例:
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;
}