2014-10-09 84 views
5

我想從我的C#應用​​程序中訪問顯微鏡。 SDK是用C++編寫的,我不能在應用程序中添加Dll作爲引用(由於它們是非託管代碼)。 因此,我發現我需要使用DllImport才能在C#中使用這些功能。如何從C#中調用C++ DLL函數#

不幸的是,這似乎是我的頭。

作爲示例的一些C++代碼的(從一個示例應用程序包含在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); 

這是如何使用它以後:

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

我如何將其轉換爲C#代碼?我已經嘗試過這樣的:

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

但基本上我沒有的我在做什麼,哪些需要下一個(的功能等需要如何定義做的想法,如何處理與「接口」在C++代碼中,是正確轉換的結構等等)。

+1

爲什麼downvote?這不是我在這裏看到的最好的問題,但我認爲它不值得讚揚,這裏提出的問題很清楚...... – ppetrov 2014-10-09 11:22:52

+0

相反,您可以創建一個[託管](http://www.c-sharpcorner。 com/UploadFile/SamTomato/managed-cpp-wrapper-for-unmanaged-code /)VC++ [wrapper](http://msdn.microsoft.com/zh-cn/library/c0sfktfw%28v=vs.110%29。 aspx),或者考慮使用反射(儘管這不是建議的...)看看[對託管和非託管代碼互操作性的建議](http://msdn.microsoft.com/zh-cn/library/ms993883.aspx )。 – 2014-10-09 11:25:15

+0

你也可以看看這篇文章:http://stackoverflow.com/questions/2637571/creating-simple-c-net-wrapper-step-by-step有一些鏈接,可以是有用的 – ppetrov 2014-10-09 11:26:19

回答

2

首先,要將那些wchar_t陣列轉換爲.NET string,您需要設置additional attributes

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

接着,CamDiscoverCameras返回指針結構,所以在.NET你將實際接收的IntPtr,然後使用Marshal.PtrToStructure方法指針轉換爲一個結構的方法:

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

並且不要忘記清理 - 從你的代碼看來,結構被分配在C++代碼的某個地方,所以你可能必須將IntPtr傳遞迴C++代碼才能釋放它。

+0

首先非常感謝你向我展示瞭如何轉換wchar_t和正確的函數聲明 但是當我使用你的代碼時,我得到一個「System.BadImageFormatException」與「試圖加載程序格式不正確(從HRESULT異常:0x8007000B)」 任何想法? – 2014-10-09 13:15:38

+0

@MarcMueller我很確定它是因爲您正在使用AnyCPU平臺目標編譯您的C#代碼。將您的項目(項目屬性 - >構建 - >平臺目標)重定向到您的Cam.dll針對其構建的相同體系結構(x86/x64),然後再試。 – Alovchin 2014-10-09 13:17:35

+0

是它 - 你的代碼工作:)真棒。 現在我會試着用我需要的其他功能來做到這一點 - 將會看到如何。 但有一件事:你張貼「將你的IntPtr傳遞給C++代碼,以便它刪除結構,因爲它似乎是在那裏分配的」 - 我沒有任何C++代碼。上面的例子只是從包含在SDK中的一個示例應用程序,在我的應用程序中,我只使用DLL,所以我不知道如何傳遞任何東西。 – 2014-10-09 13:45:44

2

你在C#中的結構定義比你更復雜一點。 查看PInvoke Interop Assistant。 https://clrinterop.codeplex.com/releases/view/14120 它對初始屬性有很大幫助。

+1

這應該是最好的評論。即使這是很好的建議,它應該是一個評論。在這種情況下,PIA不會完成任務。 – 2014-10-09 12:35:37

+0

已經嘗試過。例如,對於wchar_t,它只是說「typedef」,沒有進一步的解釋 - 或者我太愚蠢,無法使用該程序 - 在這種情況下,它不是非常直觀:) – 2014-10-09 13:17:57

+0

你說得對,我打算髮表評論,但是我不被允許。沒有足夠的聲望:( – 2014-10-09 15:33:55