如何用一个可以接受许多不同类型的参数来调用函数?

问题描述:

看一看:如何用一个可以接受许多不同类型的参数来调用函数?

[DllImport("User32.dll")] 
public static extern StatusCode DisplayConfigGetDeviceInfo(
    ref IDisplayConfigInfo a 
); 

,现在我的结构:从IDisplayConfigInfo继承:

var displayConfigTargetDeviceName = new DisplayConfigTargetDeviceName 
{ 
    header = new DisplayConfigDeviceInfoHeader 
    { 
     adapterId = targetModeInfo.adapterId, 
     id = targetModeInfo.id, 
     size = Marshal.SizeOf(typeof(DisplayConfigTargetDeviceName)), 
     type = DisplayConfigDeviceInfoType.GetTargetName, 
    } 
}; 
var configTargetDeviceName = (IDisplayConfigInfo) displayConfigTargetDeviceName; 
var retval = CCDWrapper.DisplayConfigGetDeviceInfo(ref configTargetDeviceName); 

现在有一个问题。 retval将返回“InvalidParameter”值。 这是为什么?这是因为我尝试使用界面,但我不明白为什么。

当我明确表示DisplayConfigGetDeviceInfo()接受DisplayConfigTargetDeviceName而不是接口,并直接将displayconfigTargetDeviceName传递给它时,它就可以工作。

事情是,我不想为每个结构创建8-9个重载。请注意,C++版本只有一个重载。它会从我通过的指针中找出剩下的部分。

//结构:

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] 
public struct DisplayConfigTargetDeviceName : IDisplayConfigInfo 
{ 
    public DisplayConfigDeviceInfoHeader header; 
    public DisplayConfigTargetDeviceNameFlags flags; 
    public DisplayConfigVideoOutputTechnology outputTechnology; 
    public ushort edidManufactureId; 
    public ushort edidProductCodeId; 
    public uint connectorInstance; 
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)] 
    public string monitorFriendlyDeviceName; 
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)] 
    public string monitorDevicePath; 
} 

[StructLayout(LayoutKind.Sequential)] 
public struct DisplayConfigDeviceInfoHeader 
{ 
    public DisplayConfigDeviceInfoType type; 
    public int size; 
    public LUID adapterId; 
    public uint id; 
} 

和IDisplayConfig接口是空的。

+0

+1好问题。花了一点时间来理解它! – 2013-04-20 17:47:45

感谢大卫,我能够提出巧妙的解决方案(imo),它似乎很好地工作。

[DllImport("User32.dll")] 
private static extern StatusCode DisplayConfigSetDeviceInfo(IntPtr requestPacket); 
public static StatusCode DisplayConfigSetDeviceInfo<T>(ref T displayConfig) 
    where T : IDisplayConfigInfo 
{ 
    return WrapStructureAndCall(ref displayConfig, DisplayConfigSetDeviceInfo); 
} 


[DllImport("User32.dll")] 
private static extern StatusCode DisplayConfigGetDeviceInfo(IntPtr targetDeviceName); 
public static StatusCode DisplayConfigGetDeviceInfo<T>(ref T displayConfig) 
    where T : IDisplayConfigInfo 
{ 
    return WrapStructureAndCall(ref displayConfig, DisplayConfigGetDeviceInfo); 
} 

public static StatusCode WrapStructureAndCall<T>(ref T displayConfig, 
    Func<IntPtr, StatusCode> func) where T : IDisplayConfigInfo 
{ 
    var ptr = Marshal.AllocHGlobal(Marshal.SizeOf(displayConfig)); 
    Marshal.StructureToPtr(displayConfig, ptr, false); 

    var retval = func(ptr); 

    displayConfig = (T)Marshal.PtrToStructure(ptr, displayConfig.GetType()); 

    Marshal.FreeHGlobal(ptr); 
    return retval; 
} 
+0

+1非常好。在尝试帮助时,我错过了这个可笑的方面。做得好!! – 2013-04-20 22:12:35