I use C#.net.
These is my method now:
[DllImport(DLLPath, CallingConvention = CallingConvention.Cdecl)]
unsafe public extern static int AMRecoveryModeDeviceReboot(AMRecoveryDevice device, byte[] paramByte, int u1, int u2, int u3)
I must have a Pointer in it, the AMRecoveryDevice is a struct:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
internal struct AMRecoveryDevice
{
[MarshalAs(UnmanagedType.B开发者_StackOverflowyValArray, SizeConst = 8)]
public byte[] unknown0; /* 0 */
public DeviceRestoreNotificationCallback callback; /* 8 */
public IntPtr user_info; /* 12 */
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)]
public byte[] unknown1; /* 16 */
public uint readwrite_pipe; /* 28 */
public byte read_pipe; /* 32 */
public byte write_ctrl_pipe; /* 33 */
public byte read_unknown_pipe; /* 34 */
public byte write_file_pipe; /* 35 */
public byte write_input_pipe; /* 36 */
};
Now I must have AMRecoveryDevice as a Pointer in the first method, but then it gives an error. Is it impossible?
Use ref in method declaration:
[DllImport(DLLPath, CallingConvention = CallingConvention.Cdecl)]
public extern static int AMRecoveryModeDeviceReboot(
ref AMRecoveryDevice device,
byte[] paramByte,
int u1,
int u2,
int u3)
Make device
a ref
parameter:
[DllImport(DLLPath, CallingConvention = CallingConvention.Cdecl)]
unsafe public extern static int AMRecoveryModeDeviceReboot(
ref AMRecoveryDevice device,
byte[] paramByte,
int u1,
int u2,
int u3)
A good article on how to pass data to P/Invoke calls is this one from MSDN Magazine:
Jason Clark: P/Invoke Revisited
Leaving everything else the same, you could just change the struct
to class
.
As you have specified sequential layout, this will behave just like a pointer to a struct.
IOW:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
internal class AMRecoveryDevice
{
...
}
...
[DllImport(DLLPath, CallingConvention = CallingConvention.Cdecl)]
extern static int AMRecoveryModeDeviceReboot(AMRecoveryDevice device,
byte[] paramByte, int u1, int u2, int u3)
The pattern I usually use is to make the P/invoke declaration private and use IntPtr
in place of structs. Provide a public method to handle the marshalling. (You can also get rid of unsafe this way.)
[DllImport(DLLPath, CallingConvention = CallingConvention.Cdecl)]
private extern static int AMRecoveryModeDeviceReboot(IntPtr device, byte[] paramByte, int u1, int u2, int u3)
public static int AMRecoveryModeDevice(ref AMRecoveryDevice device, byte[] paramByte, int u1, int u2, int u3) {
var ptr = Marshal.AllocHGlobal(Marshal.SizeOf(device));
Marshal.StructureToPointer(device, ptr, false);
int result = AMRecoveryModeDeviceReboot(ptr, paramByte, u1, u2, u3);
device = (AMRecoveryDevice)Marshal.PtrToStructure(ptr, typeof(AMRecoveryDevice));
Marshal.FreeHGlobal(ptr);
return result;
}
For your AMRecoveryDevice structure, you should use an IntPtr for the callback delegate too.
[MarshalAs(UnmanagedType.FunctionPtr)]
private IntPtr _callback; /* 8 */
public DeviceRestoreNotificationCallback callback {
get { return (DeviceRestoreNotificationCallback)Marsal.GetDelagateFromFunctionPointer(_callback, typeof(DeviceRestoreNotificationCallback)); }
set { _calback = Marshal.GetFunctionPointerFromDelegate(value); }
}
Not if you work in an unsafe context. See: http://msdn.microsoft.com/en-us/library/chfa2zb8(VS.71).aspx
It's not recommended in managed apps though.
精彩评论