This question already has an answer here:
这个问题已经有了答案:
- marshalling a struct containing string 2 answers
- 编组包含字符串2答案的结构体
I've looked for a while, but found no article that provides an answer to this so hopefully it isn't a duplicate.
我已经找了一段时间,但是没有一篇文章能给出答案,所以希望它不是一个副本。
I've been doing some P/Invoking with a struct, which is nice and everything, but then I saw this:
我一直在用一个结构体进行P/调用,这很好,但我发现:
char* infoString[SIDTUNE_MAX_CREDIT_STRINGS];
char * infoString[SIDTUNE_MAX_CREDIT_STRINGS];
where SIDTUNE_MAX_CREDIT_STRINGS is defined as 10.
其中sidtune_max_credit_string定义为10。
So inlining everything, the struct member is defined as:
因此,将所有的元素都包含在内,结构体成员被定义为:
char* infoString[10]
char * infoString[10]
Now this is where it gets slightly different from the other issues I've looked through to try and solve this.
这就是它与我所研究的其他问题稍有不同的地方。
The char* array contains pointers to other C strings.
char*数组包含指向其他C字符串的指针。
In this specific case, only 3 of the indexes are used while the rest are reserved. The indexes are as follows:
在这种情况下,只使用3个索引,而保留其余索引。指标如下:
-
infoString[0] = Song title
infoString[0]=歌曲标题
-
infoString[1] = Artist name
infoString[1]=艺术家的名字
-
infoString[2] = Copyright/Publisher.
infoString[2]=版权/出版商。
How would I P/Invoke this in a way I can access each of those strings from C#? Making C++ functions that return each one individually is not an option.
我如何P/调用它,以一种能够从c#访问这些字符串的方式?实现每个单独返回的c++函数不是一个选项。
1 个解决方案
#1
0
Assuming the function something like GetSongInfo(int songID, LPInfostring songinfo)
, you can define the struct
as having an array of IntPtr
. However, you will have to watch out for memory leaks as the calling function may expect you to free the memory allocated for the strings returned.
假设函数是GetSongInfo(int songID, LPInfostring songinfo),那么可以将结构定义为一个IntPtr数组。但是,您必须注意内存泄漏,因为调用函数可能希望释放为返回的字符串分配的内存。
target.h:
target.h:
typedef struct SongInfo
{
char* infoString[10];
} *LPSongInfo;
extern "C" __declspec(dllexport) int GetSongInfo(int songID, LPSongInfo info);
target.c:
target.c:
extern "C" __declspec(dllexport) int GetSongInfo(int songID, LPSongInfo demo)
{
demo->infoString[0] = "Hello world";
demo->infoString[1] = "Hello 1";
demo->infoString[2] = "Hello 2";
return TRUE;
}
P/Invoke Signature:
P / Invoke签名:
[DllImport("PInvokeDll.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern int GetSongInfo(int songID, out SongInfo ts);
[StructLayout(LayoutKind.Sequential)]
struct SongInfo
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
public IntPtr[] infoString;
};
Example Use:
使用示例:
SongInfo siStruct;
var num2 = GetSongInfo(101, out siStruct);
// copy the results to managed memory
var results = new string[10];
for (int i = 0; i < 10; i++)
{
if (siStruct.infoString[i] != IntPtr.Zero)
{
// if these were Unicode strings, this would change to PtrToSTringUni
results[i] = Marshal.PtrToStringAnsi(siStruct.infoString[i]);
}
}
// results now holds the .Net strings
// if there is an expectation of the caller to free the struct
// strings, that should happen now
As an alternative for functions which do not allocate memory, you can use a struct like the following to marshal the strings automatically. However, it will free the unmanaged memory unconditionally, which may or may not be desirable.
作为不分配内存的函数的替代方法,您可以使用如下所示的结构来自动编组字符串。然而,它将无条件释放非托管内存,这可能是可取的,也可能不是可取的。
[StructLayout(LayoutKind.Sequential)]
struct SongInfo2
{
[MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.LPStr, SizeConst = 10)]
public string[] infoString;
};
#1
0
Assuming the function something like GetSongInfo(int songID, LPInfostring songinfo)
, you can define the struct
as having an array of IntPtr
. However, you will have to watch out for memory leaks as the calling function may expect you to free the memory allocated for the strings returned.
假设函数是GetSongInfo(int songID, LPInfostring songinfo),那么可以将结构定义为一个IntPtr数组。但是,您必须注意内存泄漏,因为调用函数可能希望释放为返回的字符串分配的内存。
target.h:
target.h:
typedef struct SongInfo
{
char* infoString[10];
} *LPSongInfo;
extern "C" __declspec(dllexport) int GetSongInfo(int songID, LPSongInfo info);
target.c:
target.c:
extern "C" __declspec(dllexport) int GetSongInfo(int songID, LPSongInfo demo)
{
demo->infoString[0] = "Hello world";
demo->infoString[1] = "Hello 1";
demo->infoString[2] = "Hello 2";
return TRUE;
}
P/Invoke Signature:
P / Invoke签名:
[DllImport("PInvokeDll.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern int GetSongInfo(int songID, out SongInfo ts);
[StructLayout(LayoutKind.Sequential)]
struct SongInfo
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
public IntPtr[] infoString;
};
Example Use:
使用示例:
SongInfo siStruct;
var num2 = GetSongInfo(101, out siStruct);
// copy the results to managed memory
var results = new string[10];
for (int i = 0; i < 10; i++)
{
if (siStruct.infoString[i] != IntPtr.Zero)
{
// if these were Unicode strings, this would change to PtrToSTringUni
results[i] = Marshal.PtrToStringAnsi(siStruct.infoString[i]);
}
}
// results now holds the .Net strings
// if there is an expectation of the caller to free the struct
// strings, that should happen now
As an alternative for functions which do not allocate memory, you can use a struct like the following to marshal the strings automatically. However, it will free the unmanaged memory unconditionally, which may or may not be desirable.
作为不分配内存的函数的替代方法,您可以使用如下所示的结构来自动编组字符串。然而,它将无条件释放非托管内存,这可能是可取的,也可能不是可取的。
[StructLayout(LayoutKind.Sequential)]
struct SongInfo2
{
[MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.LPStr, SizeConst = 10)]
public string[] infoString;
};