[英]C# pInvoke with long in both 32 & 64 Bit Linux:
I need to call the Linux-function sysinfo 我需要调用Linux函数sysinfo
It's declaration is int sysinfo(struct sysinfo *info); 它的声明是int sysinfo(struct sysinfo * info); with 同
Until Linux 2.3.16, sysinfo() used to return information in the following structure: 在Linux 2.3.16之前,sysinfo()用于以以下结构返回信息:
struct sysinfo {
long uptime; /* Seconds since boot */
unsigned long loads[3]; /* 1, 5, and 15 minute load averages */
unsigned long totalram; /* Total usable main memory size */
unsigned long freeram; /* Available memory size */
unsigned long sharedram; /* Amount of shared memory */
unsigned long bufferram; /* Memory used by buffers */
unsigned long totalswap; /* Total swap space size */
unsigned long freeswap; /* swap space still available */
unsigned short procs; /* Number of current processes */
char _f[22]; /* Pads structure to 64 bytes */
};
and the sizes were given in bytes. 大小以字节为单位。
Since Linux 2.3.23 (i386), 2.3.48 (all architectures) the structure is: 从Linux 2.3.23(i386),2.3.48(所有体系结构)开始,结构为:
struct sysinfo {
long uptime; /* Seconds since boot */
unsigned long loads[3]; /* 1, 5, and 15 minute load averages */
unsigned long totalram; /* Total usable main memory size */
unsigned long freeram; /* Available memory size */
unsigned long sharedram; /* Amount of shared memory */
unsigned long bufferram; /* Memory used by buffers */
unsigned long totalswap; /* Total swap space size */
unsigned long freeswap; /* swap space still available */
unsigned short procs; /* Number of current processes */
unsigned long totalhigh; /* Total high memory size */
unsigned long freehigh; /* Available high memory size */
unsigned int mem_unit; /* Memory unit size in bytes */
char _f[20-2*sizeof(long)-sizeof(int)]; /* Padding to 64 bytes */
};
This is what I have so far: 这是我到目前为止的内容:
The function pinvoke: 该功能pinvoke:
private const string DoesntFindLibC =@"/lib/x86_64-linux-gnu/libc.so.6";
[System.Runtime.InteropServices.DllImport(DoesntFindLibC)]
private static extern int sysinfo(ref sysinfo_t info);
And the struct mapping: 和结构映射:
[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
struct sysinfo_t
{
public System.UIntPtr uptime; /* Seconds since boot */
[System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst=3)]
public System.UIntPtr [] loads; /* 1, 5, and 15 minute load averages */
public System.UIntPtr totalram; /* Total usable main memory size */
public System.UIntPtr freeram; /* Available memory size */
public System.UIntPtr sharedram; /* Amount of shared memory */
public System.UIntPtr bufferram; /* Memory used by buffers */
// [System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.
public System.UIntPtr totalswap; /* Total swap space size */
public System.UIntPtr freeswap; /* swap space still available */
public ushort procs; /* Number of current processes */
[System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst=22)]
public char[] _f; /* Pads structure to 64 bytes */
}
The problem is that "long" in C code is processor-architecture-specific, because in x86 32-Bit Linux, long's size is 32 Bit, and in x86 64-Bit Linux, it's 64 bit, so I have to take IntPtr, and because it's unsigned, I take UIntPtr. 问题在于,C代码中的“ long”是特定于处理器体系结构的,因为在x86 32位Linux中,long的大小是32位,在x86 64位Linux中是64位,所以我必须选择IntPtr,并且因为它是未签名的,所以我选择了UIntPtr。
In C#/mono however, long is always defined as Int64. 但是,在C#/ mono中,long始终定义为Int64。
Now it's a bit inconvenient to work with IntPtr. 现在使用IntPtr有点不方便。 Is there any MarshalAs attribute I could apply, or a custom marshaler that I could write so that I can actually have ulong in the struct, but it maps natively to IntPtr ? 有什么我可以应用的MarshalAs属性,或者我可以编写一个自定义的marshaler以便我实际上可以在结构中包含ulong,但是它本地映射到IntPtr吗? So that the same code works on both x86-32 and x86-64. 这样,相同的代码就可以在x86-32和x86-64上运行。
No, there isn't any marshalling magic you can do to fix this. 不,您无法采取任何编组魔术来解决此问题。
You can however hide the fields and provide property accessors: 但是,您可以隐藏字段并提供属性访问器:
using System.Runtime.InteropServices;
[StructLayoutAttribute(LayoutKind.Sequential)]
struct sysinfo_t
{
System.UIntPtr _uptime; /* Seconds since boot */
public ulong uptime {
get { return (ulong) _uptime; }
set { _uptime = new UIntPtr (value); }
}
[MarshalAs(UnmanagedType.ByValArray, SizeConst=3)]
System.UIntPtr [] _loads; /* 1, 5, and 15 minute load averages */
public ulong[] loads {
get { return new ulong [] { (ulong) _loads [0], (ulong) _loads [1], (ulong) _loads [1]) };
set { _loads = new UIntPtr [] { new UIntPtr (value [0]), new UIntPtr (value [1]), new UIntPtr (value [2]) }; }
}
// etc
}
C 'long' type is very difficult to marshal since there is no type in .NET that matches its size on all platforms. C'long'类型很难封送,因为.NET中没有在所有平台上都与其大小匹配的类型。 The problem is that the C 'long' type can be 4 bytes long on some platforms (Win32, Win64 and Linux32) and in the same time it can be 8 bytes long on the other platforms (Linux64). 问题在于,在某些平台(Win32,Win64和Linux32)上,C'long'类型的长度可以为4个字节,而在其他平台(Linux64)上,其长度可以为8个字节。 In .NET there is 'int' type which is 4 bytes long regardless of platform and there is 'long' type which is 8 bytes long regardless of platform. 在.NET中,不管平台如何,都有“ int”类型,它的长度为4个字节,而与平台无关,则是“ long”类型,它的长度为8个字节。 Neither of them can be used as a multiplatform alternative for C 'long' type and mono documentation suggest to use IntPtr as you have already found out but I find this approach very inconvenient (it is also unusable on Win64!). 它们都不能用作C'long'类型的多平台替代方案,并且单据文档建议使用IntPtr,因为您已经发现了,但是我发现这种方法非常不方便(在Win64上也无法使用!)。 Therefore I personally prefer to marshal two different sets of functions and structures , one with 'int' .NET type for platforms where C 'long' type is 4 bytes long and the other with 'long' .NET type for platforms where C 'long' type is 8 bytes long. 因此,我个人更喜欢封送两组不同的函数和结构 ,对于C'long'类型为4字节长的平台,其一组为 'int'.NET类型,对于C为'long'的平台,其另一组为'long'.NET类型。 '类型为8个字节长。 Then I just use if (IntPtr.Size == 8)
condition in runtime to decide which set should should be used. 然后,我只在运行时使用if (IntPtr.Size == 8)
条件来决定应使用哪个集合。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.