1

好的,我在 .NET 4.0 中使用 C# 中的 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 签名有问题吗?

4

2 回答 2

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 [输入,输出,可选]

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

于 2012-12-11T17:48:33.547 回答
0

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

于 2012-12-11T17:51:25.220 回答