2013-11-02 19 views
5

I çağıran bağlamını tanımlayan olası herhangi bir şekilde yoksun bir geri çağırma mekanizması olan bir (C) üçüncü parti kütüphane ile çalışmaya çalışıyorum CDECL. Ana projem C# ve sarıcı C kütüphanesi API'lerini çağırmak için bir C++/CLI projesi. C# GetFunctionPointerForDelegate yerine stdcall

Mareşal :: GetFUnctionPointerForDelegate kullanmak çalışılıyor, bu sorunu gidermek için.

void Init(Handler Callback) 
{ 
    // Create a wrapper lambda in case Callback is a non-static method. 
    instance.CreateBuffers((x, y) => Callback(x, y)); 
} 

Sonra C++/CLI kodu:

void CreateBuffers(Handler^ Callback) 
{ 
    pinCallback = GCHandle::Alloc(Callback); 

    void (*callback)(int, int) = (void (__stdcall *)(int, int))Marshal::GetFunctionPointerForDelegate(Callback).ToPointer(), 
    // Use 'callback' in third party library... 
} 

http://msdn.microsoft.com/en-us/library/367eeye0.aspx göre, Marshal gelen fonksiyon işaretçisi :: GetFunctionPointerForDelegate bir tüm bu sorun olduğunu İşte benim C# kodu stdcall işlevi, ancak C geri aramam cdecl. Burada cdecl uyumlu bir işlevi nasıl edinebilirim? UnmanagedFunctionPointer ile

+0

@JonathonReinhart, tüm bunların amacını ortadan kaldıracak, çünkü saplamadaki arama bağlamını tanımlayamayacağım. Ne arayacağımı bilmek için global bir __stdcall işlev gösterici yapmalıyım ve sonra başladığım yere döneceğim. – dsharlet

+0

Kitaplık, çeşitli geri aramalar için bir dizi işlev işaretçisi içeren bir struct argümanı kabul eden bir işlevi vardır. – dsharlet

+0

Sadece kütüphane kullanımı örneğinde bir kez ayarlamanız gerekiyor, ancak uygulamada aynı anda aktif olan çoklu kütüphane örnekleri var. – dsharlet

cevap

5

I Bunu başarmak için simpest yolu temsilci türü bildirmek olduğunu düşünüyorum C# çağrı kuralı belirtmek için bağlıyor.

[UnmanagedFunctionPointer(CallingConvention.Cdecl)] 
delegate ... 

Ardından, C++/CLI kodunuzun normal bir yerel C++ işlev işaretçisi almasını sağlayın. Temsilcinizin bir örneğini iletebilirsiniz ve temsilci bu özniteliğe sahip olduğundan, marşaler ne yapacağını bilir.

Bu GetFunctionPointerForDelegate adımı atlamak için izin verir. Aslında C++/CLI katmanının üzerinden atlamanıza izin verir, ancak bunu yapmak istemediğinizi umuyorum.

yönetilen kod sürece yönetilmeyen kod işlevi işaretçisi görebileceğiniz gibi temsilciye bir referansını korur emin olun. Bunu yapmazsanız, çöp toplayıcı, yönetilmeyen kod tarafından tutulan referansı göremediği için altından kilim çekebilir.

Bu konu tabii ki, daha önce burada ele edilmiştir. Hans Passant'ın okumaya değer bir cevabı vardır: Correct way to call a C DLL method from C#

+0

Bu, ['Marshal.GetFunctionPointerForDelegate'] için belirtilen davranışı geçersiz kılar mı (http:/"__stdcall çağrı kuralı kullanılarak" yazan /msdn.microsoft.com/en-us/library/at4fb09f.aspx)? –

+1

@Jonathon Artık GetFunctionPointerForDelegate öğesini çağırmıyorsunuz.C++ kodu hazır bir yönetilmeyen işlev işaretçisi alırdı. –

+0

Ah, tabi ki. Teşekkür ederim. –