2013-04-17 44 views
2

我需要一些幫助以下。我有一個C++ API(無法訪問源代碼),我正在努力處理返回char *屬性的方法,或者返回包含char *屬性的結構。根據API的文檔返回值如下:如何編組指向C#中一系列以null結尾的字符串的指針?

返回值
如果函數成功,返回值是一個指向一系列null結尾的字符串,一個用於主機系統上的每個項目,結束與第二個空字符。下面的示例示出了具有<null>緩衝器的內容表示終止空字符:

project1<null>project2<null>project3<null><null> 

如果函數調用失敗,返回值是NULL

時遇到的問題是,在只有C#返回的指針在這種情況下包含第一個值... project1。我怎樣才能得到完整的列表,以便能夠在託管端循環它們?

這裏的C#代碼:

[DllImport("vmdsapi.dll", EntryPoint = "DSGetProjectList", CallingConvention = CallingConvention.Cdecl)] 
    public static extern IntPtr DSGetProjectList(); 

調用方法:

IntPtr ptrProjectList = DSAPI.DSGetProjectList(); 
    string strProjectList = Marshal.PtrToStringAnsi(ptrProjectList).ToString(); 

strProjectList只包含的第一個項目。
下面是來自API的頭文件信息...

DllImport char *DSGetProjectList dsproto((void)); 

下面是一個C++我已經用於測試目的控制檯應用程序的示例代碼...

char *a; 
    a = DSGetProjectList(); 
    while(*a) { 
    printf("a=%s\n", a); 
    a += 1 + strlen(a); 
    } 

每次迭代都會正確顯示列表中的每個項目。

+1

你應該給你使用C++ API的至少簽名,也許有點C#代碼的那正在調用這個API。 – zakinster

+0

請添加您正在調用C++的c#代碼api – mmpatel009

+0

您是否仔細檢查了結果(長度)? –

回答

2

問題是,當使用Marshal.PtrToStringAnsi將C++ char *轉換爲C#字符串時,它停在第一個空字符處。

您不應該直接將char*轉換爲字符串。

你可以使用Marshal.Copy複製由IntPtrbyte[]代表的char*,然後根據需要提取儘可能多的字符串(見Matthew Watson's answer從託管數組提取字符串),但你需要獲得多串大小第一。

作爲leppie建議您也可以使用Marshal.PtrToStringAnsi提取第一個字符串,然後通過此字符串大小增加指針並提取下一個字符串,依此類推。當提取空字符串時(從最後一個NULL字符開始),您停止。

喜歡的東西:

IntPtr ptrProjectList = DSAPI.DSGetProjectList(); 
List<string> data; 
string buffer; 
do { 
    buffer = Marshal.PtrToStringAnsi(ptrProjectList); 
    ptrProjectList += buffer.size() + 1; 
    data.Add(buffer); 
}while(buffer.size() > 0) 
+1

當它停止時,爲什麼不用'strlen + 1'增加指針? – leppie

+0

是的,這是另一種可能性,但他必須在正確的時間謹慎停止,也許循環託管數組對於C#程序員來說是最簡單的。 – zakinster

+0

zakinster ...你是男人。感謝大家的幫助和快速響應。它工作100%。對此,我真的非常感激。 – Jean

0

這種字符串被稱爲Multi-String,它在Windows API中是相當普遍的。

收拾它們很費勁。你需要做的是將它編組爲char[]數組,而不是一個字符串,然後將char[]數組轉換爲一組字符串。

See here for an example solution。我已經複製的相關代碼到這個答案,但它是從我給的鏈接複製:

static List<string> MultiStringToList(char[] multistring) 
{ 
    var stringList = new List<string>(); 
    int i = 0; 

    while (i < multistring.Length) 
    { 
     int j = i; 

     if (multistring[j++] == '\0') 
      break; 

     while (j < multistring.Length) 
     { 
      if (multistring[j++] == '\0') 
      { 
       stringList.Add(new string(multistring, i, j - i - 1)); 
       i = j; 
       break; 
      } 
     } 
    } 

    return stringList; 
}