开发者

Pointer in managed Code? C#

开发者 https://www.devze.com 2023-01-07 05:27 出处:网络
I use C#.net. These is my method now: [DllImport(DLLPath, CallingConvention = CallingConvention.Cdecl)]

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.

0

精彩评论

暂无评论...
验证码 换一张
取 消