好的,我在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函数的代码时,我都会遇到以下异常:
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.
每当我在调试器之外运行相同的代码时,我都没有得到上述异常。
以下是我用来调用SetFilePointer的代码:
public enum EMoveMethod : uint
{
Begin = 0,
Current = 1,
End = 2
}
uint retvalUint = SetFilePointer(mySafeFileHandle, myLong, out myInt, EMoveMethod.Begin);
我的dllimport签名有什么问题吗?
答案 0 :(得分:2)
你的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。有关详细信息,请参阅本主题中的“备注”部分。
答案 1 :(得分:0)
可能的。 pinvoke.net让CallingConvention默认为StdCall(而不是你的Cdecl设置),因为SetFilePointer被声明为WINAPI(它是__stdcall)。调用约定不正确会损坏您的堆栈。