托管代码检查操作系统特性
对于托管代码,我们可以通过P/Invoke包装Win 32 API从而对其实现调用。例如:
/// <summary>
/// 通过P/Invoke包装Win32 API函数
/// </summary>
internal class Win32
{
[DllImport("kernel32.dll", SetLastError = true)]
public static extern IntPtr CreateWaitableTimerEx(IntPtr securityAttrs,
string timerName,
TimerFlags timerFlags, SyncObjAccessFlags desiredAccess);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool CancelWaitableTimer(IntPtr hTimer);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool CloseHandle(IntPtr handle);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern uint WaitForSingleObject(IntPtr handle, uint timeout);
/// <summary>
/// 激活计时器. 这个函数可以工作在Windows 2000及其以后的操作系统
/// </summary>
/// <param name="hTimer"></param>
/// <param name="dueTime"></param>
/// <param name="period"></param>
/// <param name="pCompletionRoutime"></param>
/// <param name="completionRoutineContext"></param>
/// <param name="resume"></param>
/// <returns></returns>
[DllImport("kernel32.dll", SetLastError=true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool SetWaitableTimer(IntPtr hTimer,
ref long dueTime, int period, IntPtr pCompletionRoutime,
IntPtr completionRoutineContext, [MarshalAs(UnmanagedType.Bool)] bool resume);
/// <summary>
/// 通过制定允许的延迟激活计时器
/// 这是Windows 7新引入的函数
/// </summary>
/// <param name="hTimer"></param>
/// <param name="dueTime"></param>
/// <param name="period"></param>
/// <param name="pCompletionRoutime"></param>
/// <param name="completionRoutineContext"></param>
/// <param name="wakeContext"></param>
/// <param name="tolerableDelay"></param>
/// <returns></returns>
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool SetWaitableTimerEx(IntPtr hTimer,
ref long dueTime, int period, IntPtr pCompletionRoutime,
IntPtr completionRoutineContext,
ref ReasonContext wakeContext, uint tolerableDelay);
}
/// 通过P/Invoke包装Win32 API函数
/// </summary>
internal class Win32
{
[DllImport("kernel32.dll", SetLastError = true)]
public static extern IntPtr CreateWaitableTimerEx(IntPtr securityAttrs,
string timerName,
TimerFlags timerFlags, SyncObjAccessFlags desiredAccess);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool CancelWaitableTimer(IntPtr hTimer);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool CloseHandle(IntPtr handle);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern uint WaitForSingleObject(IntPtr handle, uint timeout);
/// <summary>
/// 激活计时器. 这个函数可以工作在Windows 2000及其以后的操作系统
/// </summary>
/// <param name="hTimer"></param>
/// <param name="dueTime"></param>
/// <param name="period"></param>
/// <param name="pCompletionRoutime"></param>
/// <param name="completionRoutineContext"></param>
/// <param name="resume"></param>
/// <returns></returns>
[DllImport("kernel32.dll", SetLastError=true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool SetWaitableTimer(IntPtr hTimer,
ref long dueTime, int period, IntPtr pCompletionRoutime,
IntPtr completionRoutineContext, [MarshalAs(UnmanagedType.Bool)] bool resume);
/// <summary>
/// 通过制定允许的延迟激活计时器
/// 这是Windows 7新引入的函数
/// </summary>
/// <param name="hTimer"></param>
/// <param name="dueTime"></param>
/// <param name="period"></param>
/// <param name="pCompletionRoutime"></param>
/// <param name="completionRoutineContext"></param>
/// <param name="wakeContext"></param>
/// <param name="tolerableDelay"></param>
/// <returns></returns>
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool SetWaitableTimerEx(IntPtr hTimer,
ref long dueTime, int period, IntPtr pCompletionRoutime,
IntPtr completionRoutineContext,
ref ReasonContext wakeContext, uint tolerableDelay);
}
现在,我们就可以使用这些Win 32 API函数了,如果操作系统不存在某项特性,则会抛出异常,通过处理EntryPointNotFoundException和DllNotFoundException异常,判断特性是否存在,并在不存在的情况下提高备用方案。
// 使用Win 32 API函数
public void Start(long dueTime, int period)
{
ReasonContext rc = new ReasonContext();
rc.Version = 0;
rc.Flags = 1;
rc.SimpleReasonString = "MyTimer";
try
{
// 首先尝试使用Windows 7所引入的增强版本SetWaitableTimerEx
if (!Win32.SetWaitableTimerEx(_hTimer,
ref dueTime, period, IntPtr.Zero, IntPtr.Zero, ref rc, 5000))
throw new Win32Exception(Marshal.GetLastWin32Error(),
"SetWaitableTimerEx设置计时器失败.");
IsCoalescingtimer = true;
}
catch (EntryPointNotFoundException)
{
// 捕获异常,也就是当前操作系统不是Windows 7,没有SetWaitableTimerEx这一特性
IsCoalescingtimer = false;
// 提供备用方案,调用以前就有的版本SetWaitableTimer
if (!Win32.SetWaitableTimer(_hTimer, ref dueTime, period,
IntPtr.Zero, IntPtr.Zero, false))
throw new Win32Exception(Marshal.GetLastWin32Error(),
"SetWaitableTimer设置计时器失败.");
}
_waiterThread = new Thread(WaiterThreadProc);
_waiterThread.Name = "Waiter thread for WaitableTimer";
_waiterThread.Start();
}
public void Start(long dueTime, int period)
{
ReasonContext rc = new ReasonContext();
rc.Version = 0;
rc.Flags = 1;
rc.SimpleReasonString = "MyTimer";
try
{
// 首先尝试使用Windows 7所引入的增强版本SetWaitableTimerEx
if (!Win32.SetWaitableTimerEx(_hTimer,
ref dueTime, period, IntPtr.Zero, IntPtr.Zero, ref rc, 5000))
throw new Win32Exception(Marshal.GetLastWin32Error(),
"SetWaitableTimerEx设置计时器失败.");
IsCoalescingtimer = true;
}
catch (EntryPointNotFoundException)
{
// 捕获异常,也就是当前操作系统不是Windows 7,没有SetWaitableTimerEx这一特性
IsCoalescingtimer = false;
// 提供备用方案,调用以前就有的版本SetWaitableTimer
if (!Win32.SetWaitableTimer(_hTimer, ref dueTime, period,
IntPtr.Zero, IntPtr.Zero, false))
throw new Win32Exception(Marshal.GetLastWin32Error(),
"SetWaitableTimer设置计时器失败.");
}
_waiterThread = new Thread(WaiterThreadProc);
_waiterThread.Name = "Waiter thread for WaitableTimer";
_waiterThread.Start();
}
系列文章索引: