2014-10-09 36 views
5

C# uygulamamın içinden bir Mikroskop erişmeye çalışıyorum. SDK, C++ ile yazılmıştır ve Dlls'i başvurumda referans olarak ekleyemiyorum (yönetilmeyen kodlar nedeniyle). Sonuç olarak, C# ile işlevleri kullanmak için DllImport kullanmam gerekeceğini öğrendim.C++ C++ DLL işlevi nasıl yapılır C#

Maalesef bu, kafamın üzerinde bir yol gibi görünüyor.

Örnek olarak C++ kodunun bazı (örnek uygulamasından SDK dahil):

interface Camera; 
typedef Camera * CameraHandle; 

struct CameraInfo 
{ 
    wchar_t    camera_name[64];  // camera head type 
    wchar_t    controller_name[64]; // controller type 
    wchar_t    firmware_version[64]; // firmware version 
    long     lib_id;     // library ID 
    long     controller_id;   // controller ID 
    long     camera_id;    // camera ID 
    CameraHandle   handle;     // handle to opened camera 
    long     status;     // status (0 = available) 
    CameraInfo() 
    { 
    memset(this,0,sizeof(*this)); 
    } 
}; 
typedef struct CameraInfo CameraInfo; 

CamDiscoverCameras(OUT const struct CameraInfo ** info, OUT long * count); 

Ve bu daha sonra nasıl kullanıldığını geçerli:

CamResult    result;   //enum CamResult{...} 
const CameraInfo*  camera_info = NULL; 
long     camera_count = 0, pre_lib_id, pre_controller_id; 

result = CamDiscoverCameras(&camera_info, &camera_count); 

Nasıl Yaparım bunu C# koduna dönüştürmek?

[StructLayout(LayoutKind.Sequential)] 
    struct CameraInfo 
    { 
     string    camera_name;   // camera head type 
     string    controller_name;  // controller type 
     string    firmware_version;  // firmware version 
     int     lib_id;     // library ID 
     int     controller_id;   // controller ID 
     int     camera_id;    // camera ID 
     public IntPtr  handle;     // handle to opened camera 
     int     status;     // status (0 = available) 
    } 

    [DllImport("Cam.dll", EntryPoint = "CamDiscoverCameras")] 

Ama temelde ben, bu nasıl "arayüz" ile başa çıkmak için fonksiyon tanımlanması gerekir nasıl gibi (sonraki yapılması gerekenleri yapıyorum ve ne hiçbir fikrim yok: Zaten böyle bir şey denedi C++ kodunda, doğru şekilde dönüştürülen yapıdır).

+1

Neden düşüş var? Burada gördüğüm en iyi soru değil ama bir indirimi hak ettiğini düşünmüyorum, burada sorulan soru oldukça açık ... – ppetrov

+0

Bunun yerine bir [yönetilen] (http: //www.c-sharpcorner) oluşturabilirsiniz. com/UploadFile/SamTomato/yönetilen-cpp-sarmalayıcı-için-yönetilmeyen-kod /) VC++ [sarmalayıcı] (http://msdn.microsoft.com/en-us/library/c0sfktfw%28v=vs.110%29. aspx) veya yansımayı kullanmayı düşünün (bu önerilmez ...) [http://msdn.microsoft.com/en-us/library/ms993883.aspx] [Yönetilen ve Yönetilmeyen Kod Birlikte Çalışabilirlik Önerileri] 'ne bir göz atın.). –

+0

Ayrıca, bu gönderiye bir göz atabilirsiniz: http://stackoverflow.com/questions/2637571/creating-simple-c-net-wrapper-step-by-step – ppetrov

cevap

2

Öncelikle, wchar_t dizilerini .NET string dizisine dönüştürmek için additional attributes ayarlamalısınız.

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] 
struct CameraInfo 
{ 
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)] 
    string camera_name;   // camera head type 
... 

sonra, .NET aslında bir IntPtr alınması ve daha sonra Marshal.PtrToStructure yöntemi kullanılarak bir yapı bu işaretçi dönüştürme olacak şekilde, yapı bir gösterici ile döner CamDiscoverCameras yöntemi:

[DllImport("Cam.dll", EntryPoint = "CamDiscoverCameras")] 
// you can create enum of ints here and return it 
static extern int CamDiscoverCameras(out IntPtr info, out int count); 

CameraInfo DiscoverCameraInfos() 
{ 
    IntPtr info; int count; 
    int camResult = CamDiscoverCameras(out info, out count); 
    var camInfo = (CameraInfo) Marshal.PtrToStructure(info, typeof(CameraInfo)); 
    // cleanup code - pass your IntPtr to C++ code 
    // for it to delete the struct as it seems it was allocated there 
    return camInfo; 
} 

Ve temizlemeyi unutmayın - kodunuzdan, yapının C++ kodunda bir yere tahsis edildiği görülüyor, bu yüzden büyük olasılıkla IntPtr'i C++ koduna geri göndermeniz gerekiyor.

+0

Her şeyden önce bana wchar_t ve doğru işlev bildirimini nasıl dönüştürdüğünüzü gösterdiğiniz için çok teşekkür ederim. Ben kodunuzu kullandığınızda "System.BadImageFormatException" ile "Bir girişimi yanlış bir biçimde bir program yüklemek için yapıldı." (HRESULT özel durum: 0x8007000B) " Herhangi bir fikir? –

+0

@MarcMueller Oldukça eminim Çünkü C# kodunuzu AnyCPU platform hedefi ile derliyorsunuz: Projenizi (proje özellikleri -> Yapı -> Platform hedefi) yeniden projektörünüzün (x86/x64) için yapılandırdığınız aynı mimariye yeniden girin ve tekrar deneyin. – Alovchin

+0

evet öyleydi - kod çalışıyor :) harika. Şimdi ihtiyacım olan işlevlerin geri kalanıyla bunu yapmaya çalışacağım - bunun nasıl olacağını göreceksiniz. Tek bir şey olsa da: "intPtr'inizi C++ kodunuza geçirin, çünkü burada oraya tahsis edilmiş gibi görünüyordu." - C++ kodum yok. Yukarıdaki örnek, SDK'da bulunan örnek bir uygulamadaydı. Uygulamamda yalnızca dll'yi kullanıyorum, böylece bir şeye nasıl geçeceğimi bilmiyorum. –

2

C# adresindeki yapısal tanımınız sizin için biraz daha karmaşıktır. PInvoke Interop Assistant'a bir göz atın. https://clrinterop.codeplex.com/releases/view/14120 İlk özelliklerle çok yardımcı olur.

+1

Bu en iyi yorum olmalı. Bu iyi bir tavsiye olsa bile, bir yorum olmalı. Bu durumda PIA işi bitirmeyecek. –

+0

Bunu zaten denedim.Örneğin wchar_t için sadece "typedef" yazıyor ve başka bir açıklama yok - ya da programı kullanmak için çok aptalım - bu durumda çok sezgisel değil :) –

+0

Haklısın, bir yorum yapmak niyetindeyim İznim yok. Yeterli bir itibar :( –