2014-10-09 28 views
5

Próbuję uzyskać dostęp do mikroskopu z poziomu mojej aplikacji C#. SDK jest napisany w C++ i nie mogę dodać biblioteki DLL jako referencji w mojej aplikacji (z powodu niezarządzanego kodu). W rezultacie dowiedziałem się, że będę musiał użyć DllImport, aby móc używać funkcji z C#.Jak wywołać funkcję DLL C++ z C#

Niestety, wydaje mi się, że to nad moją głową.

Jako przykład niektóre kodu C++ (z app próbki zawarte w SDK):

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); 

I to jest jak jest ona wykorzystywana później:

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); 

Jak to zrobić przekonwertować to do kodu C#? Próbowałem już coś takiego:

[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")] 

Ale w zasadzie nie mam pojęcia, co robię i co trzeba zrobić następny (jak jak funkcja musi być określone, w jaki sposób radzić sobie z tym „interfejs” w kodzie C++, czy struktura jest poprawnie skonwertowana itd.).

+1

Dlaczego spadamy? To nie jest najlepsze pytanie, które tu widziałem, ale nie sądzę, że zasługuje na przyłożenie, to, o co tu poproszono, jest całkiem jasne ... – ppetrov

+0

Zamiast tego możesz stworzyć [managed] (http: //www.c-sharpcorner. com/UploadFile/SamTomato/managed-cpp-wrapper-for-unmanaged-code /) VC++ [wrapper] (http://msdn.microsoft.com/en-us/library/c0sfktfw%28v=vs.110%29. aspx) lub rozważ użycie refleksji (choć nie jest to zalecane ...) Zapoznaj się z [Zalecenia dotyczące zarządzanej i niezarządzanego współdziałania kodu] (http://msdn.microsoft.com/en-us/library/ms993883.aspx). –

+0

Możesz również zajrzeć do tego postu: http://stackoverflow.com/questions/2637571/creating-simple-c-net-wrapper-step-by-step Istnieje kilka linków, które mogą być przydatne – ppetrov

Odpowiedz

2

Przede wszystkim, aby przekonwertować te tablice wchar_t na .NET string, należy ustawić additional attributes.

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

Następnie metoda CamDiscoverCameras zwraca wskaźnik do struktury, więc w .NET będzie faktycznie otrzymaniu IntPtr a następnie przekształcenie tego wskaźnika do struktury za pomocą Marshal.PtrToStructure metody:

[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; 
} 

I nie zapomnij o oczyszczeniu - z twojego kodu wydaje się, że struktura jest przydzielana gdzieś w kodzie C++, więc prawdopodobnie musiałbyś przekazać IntPtr z powrotem do kodu C++, aby zwolnić go.

+0

Przede wszystkim dziękuję bardzo za pokazanie mi, jak przekonwertować wchar_t i prawidłową deklarację funkcji. kiedy używam twojego kodu, otrzymuję "System.BadImageFormatException" z "Próbowano załadować program o niewłaściwym formacie. (Wyjątek od HRESULT: 0x8007000B)" Każdy pomysł? –

+0

@MarcMueller Jestem prawie pewien, że to ponieważ kompilujesz swój kod C# za pomocą celu platformy AnyCPU Retarget swój projekt (właściwości projektu -> Build -> platforma docelowa) do tej samej architektury, w której zbudowano Cam.dll (x86/x64) i spróbuj ponownie – Alovchin

+0

tak, to to było - twój kod działa :) super. Teraz postaram się to zrobić z resztą potrzebnych funkcji - zobaczę, jak to działa. Jedna rzecz jednak: napisałeś "przekazać swój kod IntPtr do C++, aby usunąć strukturę, ponieważ wydaje się, że została tam przydzielona" - nie mam żadnego kodu C++. Powyższy przykład był po prostu z przykładowej aplikacji zawartej w SDK, w mojej aplikacji używam tylko biblioteki dll, więc nie mam pojęcia, jak przekazać cokolwiek do niej. –

2

Twoja definicja struct w języku C# jest nieco bardziej skomplikowana niż twoja. Spójrz na asystenta PInvoke Interop. https://clrinterop.codeplex.com/releases/view/14120 Bardzo pomaga przy początkowych atrybutach.

+1

To powinno być w najlepszym razie komentarzem. Nawet jeśli to była dobra rada, powinien to być komentarz. W takim przypadku PIA nie wykona tej pracy. –

+0

Próbowałem już tego.Na przykład dla wchar_t mówi tylko "typedef" i nie ma dalszych wyjaśnień - albo jestem po prostu zbyt głupi, żeby użyć programu - w takim przypadku nie jest to zbyt intuicyjne :) –

+0

Masz rację, zamierzałem zrobić komentarz, jednak Nie mam pozwolenia na. Za mało reputacji :( –

Powiązane problemy