Aşağıdaki ayrıntılı tanıtım için özür dilerim. P/Invoke içsellerini bildiğimden daha iyi bir içgörüye ihtiyacım var.C# P/Invoke: Fonksiyon göstergelerini içeren yapıları işaretleme
C'den C# 'a kadar işlev işaretçileri içeren yapılarımı örneklendiriyorum. Bunu yapmanın en temiz ve/veya en verimli yolu olup olmadığını bilmek isterim. döndürür
enum INTERFACES
{
FOO,
BAR
};
: Aşağıdaki numaralandırma değerleri getInterface(int)
birini geçmek zorunda
void* getInterface(int id);
: Ben aşağıdaki giriş noktası sağlar C kodlu bir yerli DLL ile arabirim ediyorum
Aşağıdaki gibi işlev işaretçileri içeren bir yapı için bir işaretçi bir işaretçi:
typedef struct IFOO
{
void (*method1)(void* self, int a, float b);
void (*method2)(void* self, int a, float b, int c);
} IFoo;
A nd burada C kullanmak nasıl: C# '
IFoo* interface = (IFoo*)getInterface(FOO);
interface->method1(obj, 0, 1.0f); // where obj is an instance of an object
// implementing the IFoo interface.
Ben P/çağır kullanılarak getInterface(int)
giriş noktası eşleştiren bir Library
sınıf var.
class Library
{
[DllImport("MyDLL"), EntryPoint="getInterface", CallingConvention=CallingConvention.Cdecl)]
public static extern IntPtr GetInterface(int id);
};
Sonra tanımlanmış:
struct IFoo
{
public M1 method1;
public M2 method2;
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void M1(IntPtr self, int a, float b);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void M2(IntPtr self, int a, float b, int c);
}
Ve bu şekilde kullanıyorum:
haritalama mı: Ben şu soru var
IntPtr address = Library.GetInterface((int)Interfaces.FOO); IFoo i = (IFoo)Marshal.PtrToStructure(address, typeof(IFoo)); i.method1(obj, 0, 1.0f): // where obj is an instance of an object // implementing the IFoo interface.
tek bir po haritalamadan daha az verimli tüm yapı
Marshal.GetDelegateForFunctionPointer()
kullanarak yapının içine inter? Çoğunlukla bir arabirim açık tüm yöntemleri gerekmez yana, ben (test edilmiş ve eserleri) yapabilirsiniz:
unsafe { IntPtr address = Library.GetInterface(id); IntPtr m2address = new IntPtr(((void**)address.toPointer())[1]); M2 method2 = (M2)Marshal.GetDelegateForFunctionPointer(m2address, typeof(M2)); method2(obj, 0, 1.0f, 1); }
kerede
Marshal.PtrToStructure()
kullanarak tüm yapıyı haritalama, orada azdır tarif ettiğimden daha ayrıntılı bir şekilde mi? Her yöntem vb için delege türlerini tanımlamaktan daha az anlam ifade etmek isterim?
DÜZENLEME: yukarıdaki kod parçacıkları açıklık ve bütünlük açısından, için, obj
void* createObject(int type)
giriş noktası ile elde edilen bir örneğidir.
EDIT2: Yöntemin bir avantajı, 1) Marshal.GetDelegateForFunctionPointer()
Framework 2.0 itibaren kullanılabilir olmasıdır. Bununla birlikte, Marshal.PrtToStructure()
her zaman mevcut olmuştur. Bu, bugünlerde 1.0 uyumluluğunu sağlamaya değer olduğundan emin değilim.
EDIT3: Ben Reflector kullanılarak oluşturulan kodu incelemek için çalıştı ama tüm ilginç ayrıntılar PtrToStructureHelper
gibi yardımcı fonksiyonları yapılır ve maruz kalmadığı beri çok bilgi vermez. Öyleyse, eğer çerçeve içersinde ne yapıldığını görebilseydim, o zaman çalışma zamanı şeyleri uzaklaştırma fırsatına sahip ve tam olarak ne, neden ve ne zaman olduğunu bilmiyorum :)
Bununla birlikte, açıklanan iki yaklaşımı karşılaştırdım. benim soruma Marshal.PtrToStructure()
yaklaşımı, Marshal.GetDelegateForFunctionPointer()
yaklaşımına kıyasla% 10 civarında bir faktör tarafından daha yavaştı; Bu, ilgi çekici olmayan tüm işlevler için IntPtr
s içeren bir yapıya sahiptir.
ayrıca kendi haddelenmiş Marshaller ile Marshal.GetDelegateForFunctionPointer()
karşılaştırılmıştır: I, çağrı yığınını temsil eden bir struct
hizalanmasını bellekte pin I asm kodlanmış trambolini kullanımı doğal tarafına adresini geçecek şekilde arama fonksiyonu kullanımları bellek alanı parametre yığını olarak (bu, cdecl
x86 çağrı sözleşmesi yığındaki tüm işlev parametrelerini geçtiği için mümkündür). Zamanlamalar eşdeğerdi.
Hakkında 1) Gerçekten neyin gerçekten yapıldığını kontrol etmenin mümkün olup olmadığını bilmiyorum: Optimizatör, yapının sadece 1 delegesinin kullanıldığını anlayabilir. Neyse en azından yeterince temiz görünüyor. –
@Gregory Bence bu olası değil. Ancak kod çözmek ve kesin olarak öğrenmek için .NET reflektörünü kullanabilirsiniz. –