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());

また、ドキュメントから注意してください:

l移動距離 [インチ]

ファイル ポインターを移動するバイト数を指定する符号付き値の下位 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では、SetFilePointer が WINAPI (__stdcall) として宣言されているため、CallingConvention を (Cdecl 設定ではなく) StdCall にデフォルト設定できます。呼び出し規則が正しくないと、スタックが破損します。

于 2012-12-11T17:51:25.220 に答える