L’utilizzo di SetFilePointer in C # ha distriggersto lo stack

Ok, sto usando la funzione SetFilePointer in C # con .NET 4.0. Di seguito sono riportati i dllimports che ho usato per chiamare questa funzione:

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

Ogni volta che eseguo il codice che utilizza la funzione SetFilePointer nel debugger ottengo questa eccezione:

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.

Ogni volta che eseguo lo stesso codice all’esterno del debugger non ottengo l’eccezione di cui sopra.

Di seguito è riportato il codice che sto usando per effettuare le chiamate a SetFilePointer:

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

C’è qualcosa di sbagliato nelle mie firme di dllimport?

La tua firma P / Invoke è un po ‘spenta:

Ecco la definizione Win32:

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

Ed ecco il P / Invoke con il tuo enum specificato:

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

EDIT: Oh, e qualche codice di prova:

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

Nota anche dai documenti:

lDistanceToMove [in]

Il basso ordine di 32 bit di un valore firmato che specifica il numero di byte per spostare il puntatore del file. Se lpDistanceToMoveHigh non è NULL, lpDistanceToMoveHigh e lDistanceToMove formano un singolo valore firmato a 64 bit che specifica la distanza da spostare. Se lpDistanceToMoveHigh è NULL, lDistanceToMove è un valore firmato a 32 bit. Un valore positivo per lDistanceToMove sposta il puntatore del file in avanti nel file e un valore negativo sposta il puntatore del file indietro.

lpDistanceToMoveHigh [in, out, facoltativo]

Un puntatore ai 32 bit di ordine elevato della distanza a 64 bit con segno da spostare. Se non hai bisogno dei 32 bit di ordine elevato, questo puntatore deve essere impostato su NULL. Quando non è NULL, questo parametro riceve anche il DWORD di ordine elevato del nuovo valore del puntatore del file. Per ulteriori informazioni, consultare la sezione Note in questo argomento.

Probabile. pinvoke.net consente a CallingConvention di impostare automaticamente StdCall (anziché l’impostazione Cdecl) e poiché SetFilePointer è dichiarato come WINAPI (che è __stdcall). La convenzione di chiamata errata danneggerà il tuo stack.