2009-08-24 45 views
5

Tôi đang gặp một số sự cố khi sắp xếp một con trỏ tới một chuỗi các chuỗi. Có vẻ vô hại như thế này:Biến đổi con trỏ thành một mảng các chuỗi

typedef struct 
{ 
    char* listOfStrings[100]; 
} UnmanagedStruct; 

này là thực sự nhúng bên trong cấu trúc khác như thế này:

typedef struct 
{ 
    UnmanagedStruct umgdStruct; 
} Outerstruct; 

unmanaged code gọi lại vào mã số quản lý và trả về Outerstruct như một IntPtr với bộ nhớ được phân bổ và các giá trị điền vào .

Managed thế giới:

[StructLayout(LayoutKind.Sequential)] 
public struct UnmanagedStruct 
{ 
    [MarshalAs(UnmanagedType.LPArray, ArraySubType=UnmanagedType.LPStr, SizeConst=100)] 
    public string[] listOfStrings; 
} 

[StructLayout(LayoutKind.Sequential)] 
public struct Outerstruct 
{ 
    public UnmanagedStruct ums; 
} 

public void CallbackFromUnmanagedLayer(IntPtr outerStruct) 
{ 
    Outerstruct os = Marshal.PtrToStructure(outerStruct, typeof(Outerstruct)); 
    // The above line FAILS! it throws an exception complaining it cannot marshal listOfStrings field in the inner struct and that its managed representation is incorrect! 
} 

Nếu tôi thay đổi listOfStrings chỉ đơn giản là một IntPtr sau đó Marshal.PtrToStructure hoạt động nhưng bây giờ tôi không thể rip vào listOfStrings và trích xuất từng chuỗi một.

Trả lời

1

OK .. Tôi dường như đã nhận nó để làm việc. Nên marshaled như IntPtr []

Điều này dường như làm việc:

[StructLayout(LayoutKind.Sequential)] 
public struct UnmanagedStruct 
{ 
    [MarshalAs(UnmanagedType.ByValArray, SizeConst=100)] 
    public IntPtr[] listOfStrings; 
} 

for (int i = 0; i < 100; ++i) 
{ 
    if (listOfstrings[i] != IntPtr.Zero) 
     Console.WriteLine(Marshal.PtrToStringAnsi(listOfStrings[i])); 
}  
+0

ByValArray == mảng tại chỗ, LPArray == một con trỏ tới một mảng. Mặc dù SizeConst vẫn nên làm việc với một LPArray, do đó, lỗi khi marshaling là một chút kỳ lạ. –

+0

Ồ, điều đó cũng sẽ hoạt động nếu bạn có chuỗi công khai [] listOfStrings, đó là ByValArray tạo nên sự khác biệt mà tôi tin tưởng. –

4

Làm bất cứ điều gì, nhưng một chuỗi rất cơ bản là phức tạp và đầy đủ các trường hợp phụ khó phát hiện. Nó thường là tốt nhất để đi với các tuyến đường an toàn/đơn giản trong định nghĩa struct và thêm một số thuộc tính wrapper để dọn dẹp những thứ lên một chút.

Trong trường hợp này tôi sẽ đi với mảng IntPtr và sau đó thêm một tài sản wrapper có thể chuyển đổi chúng thành các chuỗi

[StructLayout(LayoutKind.Sequential)] 
public struct UnmanagedStruct 
{ 
    [MarshalAs(UnmanagedType.LPArray, ArraySubType=UnmanagedType.LPStr, SizeConst=100)] 
    public IntPtr[] listOfStrings; 

    public IEnumerable<string> Strings { get { 
     return listOfStrings.Select(x =>Marshal.PtrToStringAnsi(x)); 
    } 
} 
+0

Jared Cảm ơn để phê chuẩn! Tôi đã đăng câu trả lời cho câu hỏi của riêng tôi ngay bây giờ trước khi nhìn thấy câu trả lời của bạn. Một câu hỏi - làm cách nào để định dạng mã của tôi trong bài đăng? Tất cả họ đều có vẻ bối rối và ai đó phải chỉnh sửa và chỉnh sửa nó mọi lúc. – Dilip

+0

@Dilip, chọn đoạn mã của bạn và nhấn CTRL + K. Điều đó sẽ sửa định dạng bằng cách thụt lề tất cả mọi thứ 4 spcaes – JaredPar

+0

@Jared: chỉ cần theo dõi nhanh. Mã tiếp tục bị đánh bom nếu tôi sử dụng UnmanagedType.LPArray. Chỉ UnmanagedType.ByValArray hoạt động. Bây giờ tôi hiểu những gì KeeperOfTheSoul đã gợi ý trong ý kiến ​​của mình. – Dilip

Các vấn đề liên quan