我正在尝试从 C#调用Shell_NotifyIcon
函数 [ 1 ]。该函数的一个参数是指向NOIFYICONDATA
结构[ 2 ]的指针。该结构包含TCHAR
数组、指针,并且有 4 个不同的版本(取决于使用的 OS/API)。在将结构 ( cbSize
) 中的第一个字段传递给Shell_NotifyIcon
函数之前,调用者必须将其设置为结构的大小(以字节为单位)。
我目前的方法是使用 4 个类:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
[BestFitMapping(false, ThrowOnUnmappableChar = true)]
public class NotifyIconData { ... }
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
[BestFitMapping(false, ThrowOnUnmappableChar = true)]
public class NotifyIconData2 : NotifyIconData { ... }
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
[BestFitMapping(false, ThrowOnUnmappableChar = true)]
public class NotifyIconData3 : NotifyIconData2 { ... }
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
[BestFitMapping(false, ThrowOnUnmappableChar = true)]
public class NotifyIconData4 : NotifyIconData3 { ... }
在构造函数中NotifyIconData
我使用Marshal.SizeOf(this.GetType());
来确定结构的大小。结果是正确的(至少在未管理的 Unicode/Ansi/x86/x64 构建中它与 , , 相同。NOTIFYICONDATA_V1_SIZE
这种NOTIFYICONDATA_V2_SIZE
方法的原因是我不想使用幻数,特别是因为填充已完成,因此需要计算结构的正确大小。在字段的实现中还涉及到一个小技巧。该字段可以是 64 个字符的数组(版本 1),也可以是 128个字符的数组(版本 2)。模拟该类包含以下字段定义:NOTIFYICONDATA_V3_SIZE
sizeof(NOTIFYICONDATAW)
szTip
TCHAR
TCHAR
NotifyIconData
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)]
protected string szTip;
在NotifyIconData2
类中,我使用以下定义“扩展”该字段:
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)]
private string szTipExtension;
该字段是通过一个虚拟属性访问的,该属性处理实际值到两个字段的分段。
然后将这些类与Shell_NotifyIcon
声明如下的函数一起使用:
[UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Auto)]
[return: MarshalAs(UnmanagedType.Bool)]
private delegate bool ShellNotifyIconFunction(
[In, MarshalAs(UnmanagedType.U4)] uint dwMessage,
[In] NotifyIconData lpdata);
人们会相信我现在可以将一个NotifyIconData4
实例传递给该函数。在编译时这有效(如预期的那样)。但在运行时我得到一个 MDAFatalExecutionEngineError
异常。当我将参数类型从更改NotifyIconData
为NotifyIconData4
调用成功并且它可以工作。
Marshaller 似乎使用静态NotifyIconData
类型而不是NotifyIconData4
动态类型来编组数据。谁能证实这一点?或者任何人都可以向我指出有关编组如何与继承一起工作的信息?