我尝试了在Using SetFilePointer in C# has unblanced the stack中提出的解决方案来移动文件的指针并且它有效。唯一的问题是,当读取设备而不是文件时,setfilepointer将指针放在包含所需地址的扇区的开头,而不是将其放在所需的地址本身。不知道为什么。 但我的问题是另一个问题。根据我已经阅读的文档,如果您不需要使用moveDistanceHighBits,因为只需要低位字节来解决您想要的偏移量,您必须将moveDistanteHighBits设置为null。但我不知道该怎么做。 有人可以帮忙吗?
答案 0 :(得分:2)
这不仅仅是因为winapi函数的特殊情况。与25年前使用的C编译器不同,C#很好地支持64位整数。而且风险太大了。您想要编写一个包装器方法,以便在winapi函数失败时正确抛出异常。永远不要跳过它。这样做:
using System;
using System.IO;
using System.Runtime.InteropServices;
using Microsoft.Win32.SafeHandles;
public class NativeMethods {
public static void SetFilePointer(SafeFileHandle hFile, long dist, SeekOrigin method) {
int lodist = (int)dist;
int hidist = (int)(dist >> 32);
int retval = SetFilePointer(hFile, lodist, ref hidist, method);
if (retval == -1) throw new System.ComponentModel.Win32Exception();
}
[DllImport("Kernel32.dll", SetLastError = true)]
private static extern int SetFilePointer(SafeFileHandle hFile,
int distlo, ref int disthi, SeekOrigin method);
}
}
请注意,您根本不需要根据它进行调整。您想要使用其中一个采用IntPtr或SafeHandle的FileStream构造函数。例如This one。现在您只需使用FileStream.Seek()。
答案 1 :(得分:1)
您可以更改PInvoke签名以使用IntPtr
,然后在您想要传递IntPtr.Zero
时传递NULL
。新签名看起来像这样:
[DllImport("kernel32.dll", EntryPoint="SetFilePointer", SetLastError=true)]
static extern uint SetFilePointer(
[In] Microsoft.Win32.SafeHandles.SafeFileHandle hFile,
[In] int lDistanceToMove,
[In] IntPtr lpDistanceToMoveHigh,
[In] EMoveMethod dwMoveMethod);
这是有效的,因为在两个定义中,您传递指针但使用IntPtr
可以控制实际的指针值。当您使用ref
时,您必须拥有一个现有的局部变量,编译器将获取其地址。
如果您需要从NULL
来电回复/接收值(SetFilePointer
除外),您可以这样做:
int nValue = ...; // Value to pass for lpDistanceToMoveHigh
IntPtr pInt = IntPtr.Zero;
try
{
pInt = Marshal.AllocHGlobal ( sizeof ( int ) );
Marshal.WriteInt32 ( pInt, nValue );
// Call SetFilePointer(); upon successful return,
// you can read the value returned for lpDistanceToMoveHigh
nValue = Marshal.ReadInt32 ( pInt );
// ...
}
finally
{
if ( pInt != IntPtr.Zero )
Marshal.FreeHGlobal ( pInt );
}