轉--C#呼叫C++DLL傳遞結構體陣列的終極解決方案
在專案開發時,要呼叫C++封裝的DLL,普通的型別C#上一般都對應,只要用DllImport傳入從DLL中引入函式就可以了。但是當傳遞的是結構體、結構體陣列或者結構體指標的時候,就會發現C#上沒有型別可以對應。這時怎麼辦,第一反應是C#也定義結構體,然後當成引數傳弟。然而,當我們定義完一個結構體後想傳遞引數進去時,會拋異常,或者是傳入了結構體,但是返回值卻不是我們想要的,經過除錯跟蹤後發現,那些值壓根沒有改變過,程式碼如下。
- [DllImport("workStation.dll")]
- privatestaticexternbool fetchInfos(Info[] infos);
- publicstruct Info
- {
- publicint OrderNO;
- publicbyte[] UniqueCode;
- publicfloat CpuPercent;
- };
- privatevoid buttonTest_Click(object sender, EventArgs e)
- {
- try
- {
- Info[] infos=new
- if (fetchInfos(infos))
- {
- MessageBox.Show("Fail");
- }
- else
- {
- string message = "";
- foreach (Info info in infos)
- {
- message += string
- info.OrderNO,
- Encoding.UTF8.GetString(info.UniqueCode),
- info.CpuPercent
- );
- }
- MessageBox.Show(message);
- }
- }
- catch (System.Exception ex)
- {
- MessageBox.Show(ex.Message);
- }
- }
後來,經過查詢資料,有文提到對於C#是屬於託管記憶體,現在要傳遞結構體陣列,是屬性非託管記憶體,必須要用Marsh指定空間,然後再傳遞。於是將結構體變更如下。
- [StructLayoutAttribute(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
- publicstruct Info
- {
- publicint OrderNO;
- [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
- publicbyte[] UniqueCode;
- publicfloat CpuPercent;
- };
但是經過這樣的改進後,執行結果依然不理想,值要麼出錯,要麼沒有被改變。這究竟是什麼原因?不斷的搜資料,終於看到了一篇,裡面提到結構體的傳遞,有的可以如上面所做,但有的卻不行,特別是當引數在C++中是結構體指標或者結構體陣列指標時,在C#呼叫的地方也要用指標來對應,後面改進出如下程式碼。
- [DllImport("workStation.dll")]
- privatestaticexternbool fetchInfos(IntPtr infosIntPtr);
- [StructLayoutAttribute(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
- publicstruct Info
- {
- publicint OrderNO;
- [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
- publicbyte[] UniqueCode;
- publicfloat CpuPercent;
- };
- privatevoid buttonTest_Click(object sender, EventArgs e)
- {
- try
- {
- int workStationCount = 128;
- int size = Marshal.SizeOf(typeof(Info));
- IntPtr infosIntptr = Marshal.AllocHGlobal(size * workStationCount);
- Info[] infos = new Info[workStationCount];
- if (fetchInfos(infosIntptr))
- {
- MessageBox.Show("Fail");
- return;
- }
- for (int inkIndex = 0; inkIndex < workStationCount; inkIndex++)
- {
- IntPtr ptr = (IntPtr)((UInt32)infosIntptr + inkIndex * size);
- infos[inkIndex] = (Info)Marshal.PtrToStructure(ptr, typeof(Info));
- }
- Marshal.FreeHGlobal(infosIntptr);
- string message = "";
- foreach (Info info in infos)
- {
- message += string.Format("OrderNO={0}\r\nUniqueCode={1}\r\nCpu={2}",
- info.OrderNO,
- Encoding.UTF8.GetString(info.UniqueCode),
- info.CpuPercent
- );
- }
- MessageBox.Show(message);
- }
- catch (System.Exception ex)
- {
- MessageBox.Show(ex.Message);
- }
- }
在BCB中如果沒有位元組對齊的話,有時會比一般的結構體大小多出2兩個位元組。因為BCB預設的是2位元組排序,而VC是預設1 個位元組排序。要解決該問題,要麼在BCB的結構體中增加位元組對齊,要麼在C#中多開兩個位元組(如果有多的話)。位元組對齊程式碼如下。
- #pragma pack(push,1)
- struct Info
- {
- int OrderNO;
- char UniqueCode[32];
- float CpuPercent;
- };
- #pragma pack(pop)
用Marsh.AllocHGlobal為結構體指標開闢記憶體空間,目的就是轉變化非託管記憶體,那麼如果不用Marsh.AllocHGlobal,還有沒有其他的方式呢?
其實,不論C++中的是指標還是陣列,最終在記憶體中還是一個一個位元組儲存的,也就是說,最終是以一維的位元組陣列形式展現的,所以我們如果開一個等大小的一維陣列,那是否就可以了呢?答案是可以的,下面給出了實現。
- [DllImport("workStation.dll")]
- privatestaticexternbool fetchInfos(IntPtr infosIntPtr);
- [DllImport("workStation.dll")]
- privatestaticexternbool fetchInfos(byte[] infos);
- [StructLayoutAttribute(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
- publicstruct Info
- {
- publicint OrderNO;
- [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
- publicbyte[] UniqueCode;
- publicfloat
相關推薦
轉--C#呼叫C++DLL傳遞結構體陣列的終極解決方案
在專案開發時,要呼叫C++封裝的DLL,普通的型別C#上一般都對應,只要用DllImport傳入從DLL中引入函式就可以了。但是當傳遞的是結構體、結構體陣列或者結構體指標的時候,就會發現C#上沒有型別可以對應。這時怎麼辦,第一反應是C#也定義結構體,然後當成引數傳弟。然而,當
結構體指標作函式引數(C# 呼叫C++ 的DLL)
1、C++結構體定義: #pragma pack(1) struct Person { #define Count_favoriteNumbers 6 int id; fl
c#呼叫C/C++ DLL,傳入指標陣列(指標指向自定的結構體)
來源:http://bbs.csdn.net/topics/380165851 依靠以下文章:解決問題。 、、、、、、、、、、、、、、、、、、、、 可以用Marshal.StruectToPtr哦。 、、、、、、、、、、、、、、 [StructLayout(Layo
C# 呼叫dll 封送結構體 結構體陣列
一. 結構體的傳遞 cpp 程式碼 #define JNAAPI extern "C" __declspec(dllexport) // C方式匯出函式 typedef struct { int osVersion; int majorVe
C#呼叫c++Dll結構體陣列指標的問題
C#呼叫c++dll檔案是一件很麻煩的事情,首先面臨的是資料型別轉換的問題,相信經常做c#開發的都和我一樣把學校的那點c++底子都忘光了吧(語言特性類)。 網上有一大堆得轉換對應表,也有一大堆的轉換例項,但是都沒有強調一個更重要的問題,就是c#資料型別和c++資料型別佔
python呼叫C++,傳遞結構體與結構體指標,以及巢狀結構體
#include<iostream>using namespace std;//該檔名稱:cpptest.cpp//終端下編譯指令://g++ -o cpptest.so -shared -fPIC cpptest.cppstruct sub_struct{
C# 向 C++ DLL中傳遞結構體,包含二維陣列,一維陣列,VS2013下測試通過。
需求是這樣的: C++中需要結構體如下: PS:使用的是MFC 靜態 DLL工程! // struct HCNetConnectData {//CHAR * HCNetServerIP;//INT HCNetServerPort;//CHAR * HCNetServe
[轉]C#呼叫C++ DLL
在開發過程中經常需要在C#中呼叫C++編寫的DLL,中間碰到過一些問題,這裡做個總結,方便以後參考。 型別對照問題 記憶體釋放問題 版本問題(x86與x64) 編譯問題(靜態與動態) 資源載入問題 異常捕獲與問題定位 型別對照問題 c#呼叫c++方法時,首先要在類中定義
C#呼叫C++的dll傳遞二維陣列
1.C++中標頭檔案.h extern "C" MATHFUNCSDLL_API int __stdcall CallTest(int** arr, int rows, int cols); 2.C++中原始檔.cpp int __stdcall CallTest
C#呼叫C++編寫的DLL函式各種引數傳遞問題
[System.Security.SuppressUnmanagedCodeSecurity] // We won't use this maliciously [DllImport("User32.dll", CharSet=CharSet.Auto)] public static extern
C#呼叫C/C++動態庫 封送結構體,結構體陣列
一. 結構體的傳遞 Cpp程式碼 #define JNAAPI extern "C" __declspec(dllexport) // C方式匯出函式 typedef struct { int osVersion;
用JNI從C傳遞結構體到JAVA
typedef struct Foo { int len; char name[100]; } Foo_t; JNIEXPORT jint JNICALL Java_TestJNI_foo(JNIEnv *env, jobject obj, jobject fooObj) { Foo
golang日期轉字串,仿照C#中的日期格式結構體
1、日期格式集合、日期轉字串方法 package util import ( "strings" "time" ) //日期格式:模仿java中的結構體 type DateStyle string const ( MM_DD
C#呼叫C/C++動態庫,封裝各種複雜結構體。
現在公司要做一個使用C#程式呼叫C++的一個DLL庫,解析檔案的功能。所以在網上找了一些資料。 一、結構體傳遞 #define JNAAPI extern "C" __declspec(dllexport) // C方式匯出函式 typedef str
C#呼叫C/C++ DLL 引數傳遞和回撥函式的總結
Int型傳入: Dll端: extern "C" __declspec(dllexport) int Add(int a, int b) { return a+b; } C#端: [DllImport("aeClient2.0.dll", CallingCo
C#呼叫C++ 平臺呼叫P/Invoke 結構體--輸入輸出引數、返回值、返出值、結構體陣列作為引數【五】
【1】結構體作為輸入輸出引數 C++程式碼: typedef struct _testStru1 { int iVal; char cVal; __int64 llVal; }testS
C#呼叫C++ 平臺呼叫P/Invoke 結構體--含有內建資料型別的一維、二維陣列、字串指標【六】
【1】結構體中含有內建資料型別的一維陣列 C++程式碼: typedef struct _testStru3 { int iValArrp[30]; WCHAR szChArr[30];
C++ 字串 15-- 18.41.結構體與string string類的呼叫 引數通過引用的方式呼叫
#include <iostream> #include <string> using namespace std; /*--------------------------------- 18.41.結構體與string string類的呼叫 引數通
C語言中,隱藏結構體的細節
all printf span 包括 strcpy () 創建 提高 結構體指針 我們都知道,在C語言中,結構體中的字段都是可以訪問的。或者說,在C++ 中,類和結構體的主要區別就是類中成員變量默認為private,而結構體中默認為public。結構體的這一個特性,導致結構