在C#中使用SetFilePointer已经取消了堆栈

好的,我在C#和.NET 4.0中使用SetFilePointer函数。 以下是我用来调用此函数的dllimports:

[DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl)] static extern uint SetFilePointer([In] SafeFileHandle hFile, [In] long lDistanceToMove, [Out] out int lpDistanceToMoveHigh, [In] EMoveMethod dwMoveMethod); 

每当我运行在调试器中使用SetFilePointer函数的代码时,我都会遇到以下exception:

PInvokeStackImbalance was detected Message: A call to PInvoke function 'MyDiskStuff!MyDiskStuff.HardDisk::SetFilePointer' has unbalanced the stack. This is likely because the managed PInvoke signature does not match the unmanaged target signature. Check that the calling convention and parameters of the PInvoke signature match the target unmanaged signature.

每当我在调试器外部运行相同的代码时,我都没有得到上述exception。

下面是我用来调用SetFilePointer的代码:

 public enum EMoveMethod : uint { Begin = 0, Current = 1, End = 2 } uint retvalUint = SetFilePointer(mySafeFileHandle, myLong, out myInt, EMoveMethod.Begin); 

我的dllimport签名有什么问题吗?

你的P / Invoke签名有点偏差:

这是Win32的定义:

 DWORD WINAPI SetFilePointer( _In_ HANDLE hFile, _In_ LONG lDistanceToMove, _Inout_opt_ PLONG lpDistanceToMoveHigh, _In_ DWORD dwMoveMethod ); 

这是指定枚举的P / Invoke:

 [DllImport("kernel32.dll", EntryPoint="SetFilePointer")] static extern uint SetFilePointer( [In] Microsoft.Win32.SafeHandles.SafeFileHandle hFile, [In] int lDistanceToMove, [In, Out] ref int lpDistanceToMoveHigh, [In] EMoveMethod dwMoveMethod) ; 

编辑:哦,还有一些测试代码:

 var text = "Here is some text to put in the test file"; File.WriteAllText(@"c:\temp\test.txt", text); var file = File.Open(@"c:\temp\test.txt", FileMode.OpenOrCreate); int moveDistance = 10; int moveDistanceHighBits = 0; uint retvalUint = SetFilePointer(file.SafeFileHandle, moveDistance, ref moveDistanceHighBits, EMoveMethod.Begin); Debug.Assert(Encoding.ASCII.GetBytes(text)[moveDistance] == file.ReadByte()); 

另请注意文档:

lDistanceToMove [in]

带符号值的低32位,指定移动文件指针的字节数。 如果lpDistanceToMoveHigh不为NULL,则lpDistanceToMoveHigh和lDistanceToMove形成一个64位有符号值,用于指定要移动的距离。 如果lpDistanceToMoveHigh为NULL,则lDistanceToMove是32位有符号值。 lDistanceToMove的正值将文件指针向前移动到文件中,负值将文件​​指针移回。

lpDistanceToMoveHigh [in,out,optional]

指向要移动的带符号64位距离的高阶32位的指针。 如果不需要高位32位,则必须将此指针设置为NULL。 当不为NULL时,此参数还接收文件指针的新值的高阶DWORD。 有关更多信息,请参阅本主题中的“备注”部分。

有可能。 pinvoke.net让CallingConvention默认为StdCall(而不是你的Cdecl设置),因为SetFilePointer被声明为WINAPI(它是__stdcall)。 调用约定不正确会损坏您的堆栈。