The last notification related API that we will look at for this time is CeGetUserNotification. As its name implies this function returns information on a previously created notification. The function takes a notification handle as input and returns a byte array containing an instance of a CE_NOTIFICATION_INFO_HEADER. This structure points to two other structures that are allocated in the same buffer, CE_NOTIFICATION_TRIGGER and CE_USER_NOTIFICATION.
[DllImport("CoreDLL.dll", SetLastError = false, EntryPoint="CeGetUserNotification")]
public static extern bool GetUserNotification(IntPtr hNotification, uint BufferSize, out uint BytesNeeded, byte[] Buffer);
Calling GetUserNotification passing null values and a valid notification handle will return the bytes needed for the byte buffer. You then call GetUserNotification once more passing both a notification handle as well as a byte buffer.
GetUserNotification(hNotification, 0, out Size, null);
Buf = new byte[Size];
GetUserNotification(hNotification, Size, out Size, Buf)
Had we been doing this in c++ then casting the byte array into a CE_NOTIFICATION_INFO_HEADER would be as easy as 1-2-3.. Casting this C-style array using CSharp is quite but not quite as easy. Basically we have to read the buffer byte by byte, using the data to set the values of an instance of the structure. I choose to do this using the structures constructor. My implementation of CE_NOTIFICATION_INFO_HEADER is found below.
[StructLayout(LayoutKind.Sequential)]
public class CE_NOTIFICATION_INFO_HEADER
{
[MarshalAs(UnmanagedType.U4)]
public uint hNotification;
[MarshalAs(UnmanagedType.U4)]
public uint dwStatus;
public CE_NOTIFICATION_TRIGGER cent;
public CE_USER_NOTIFICATION ceun;
public CE_NOTIFICATION_INFO_HEADER(byte[] Buf, uint Size)
{
int Index = 0;
try
{
this.hNotification = BitConverter.ToUInt32(Buf, Index);
Index += 4;
this.dwStatus = BitConverter.ToUInt32(Buf, Index);
Index += 4;
uint pcent = BitConverter.ToUInt32(Buf, Index);
Index += 4;
uint pceun = BitConverter.ToUInt32(Buf, Index);
Index += 4;
if (pcent > 0 && Buf[Index] == Marshal.SizeOf(new CE_NOTIFICATION_TRIGGER()))
this.cent = new CE_NOTIFICATION_TRIGGER(Buf, Size, ref Index);
if (pceun > 0)
this.ceun = new CE_USER_NOTIFICATION(Buf, Size, ref Index);
}
catch (Exception ex)
{
throw ex;
}
}
}
As you can see I've overloaded the constructors of both CE_NOTIFICATION_TRIGGER and CE_USER_NOTIFICATION to be able to create instances from a byte array. Here are the final implementations of both structures.
[StructLayout(LayoutKind.Sequential)]
public class CE_NOTIFICATION_TRIGGER
{
public UInt32 Size = 0;
[MarshalAs(UnmanagedType.U4)]
public CeNotificationType Type;
[MarshalAs(UnmanagedType.U4)]
public CeNotificationEvent Event;
[MarshalAs(UnmanagedType.LPWStr)]
public string pApplication;
[MarshalAs(UnmanagedType.LPWStr)]
public string pArgs;
public SYSTEMTIME StartTime;
public SYSTEMTIME EndTime;
public CE_NOTIFICATION_TRIGGER()
{
}
public CE_NOTIFICATION_TRIGGER(byte[] Buf, uint Size, ref int Index)
{
int iEndOfString;
System.Text.UnicodeEncoding enc = new UnicodeEncoding();
uint lpszApp = 0;
uint lpszArgs = 0;
this.Size = BitConverter.ToUInt32(Buf, Index);
Index += 4;
this.Type = (CeNotificationType)BitConverter.ToUInt32(Buf, Index);
Index += 4;
this.Event = (CeNotificationEvent)BitConverter.ToUInt32(Buf, Index);
Index += 4;
lpszApp = BitConverter.ToUInt32(Buf, Index);
Index += 4;
lpszArgs = BitConverter.ToUInt32(Buf, Index);
Index += 4;
this.StartTime = new SYSTEMTIME(Buf, Index);
Index += 16;
this.EndTime = new SYSTEMTIME(Buf, Index);
Index += 16;
if (lpszApp > 0)
{
iEndOfString = WinCE.WinCE.findEndOfString(Buf, Index, (int)Size);
this.pApplication = enc.GetString(Buf, Index, iEndOfString - Index - 2);
Index = iEndOfString;
}
if (lpszArgs > 0)
{
iEndOfString = WinCE.WinCE.findEndOfString(Buf, Index, (int)Size);
this.pArgs = enc.GetString(Buf, Index, iEndOfString - Index - 2); // Stupid solution to double null ending..
Index = iEndOfString;
}
}
}
[StructLayout(LayoutKind.Sequential)]
public class CE_USER_NOTIFICATION
{
[MarshalAs(UnmanagedType.U4)]
public PUN_FLAGS ActionFlags;
[MarshalAs(UnmanagedType.LPTStr)]
public string sDialogTitle;
[MarshalAs(UnmanagedType.LPTStr)]
public string sDialogText;
[MarshalAs(UnmanagedType.LPTStr)]
public string sSound;
[MarshalAs(UnmanagedType.U4)]
public uint nMaxSound;
[MarshalAs(UnmanagedType.U4)]
public uint Reserved;
public CE_USER_NOTIFICATION()
{
}
public CE_USER_NOTIFICATION(byte[] Buf, uint Size, ref int Index)
{
int iEndOfString;
System.Text.UnicodeEncoding enc = new UnicodeEncoding();
this.ActionFlags = (PUN_FLAGS)BitConverter.ToUInt32(Buf, Index);
Index += 4;
uint lpszDialogTitle = BitConverter.ToUInt32(Buf, Index);
Index += 4;
uint lpszDialogText = BitConverter.ToUInt32(Buf, Index);
Index += 4;
uint lpszSound = BitConverter.ToUInt32(Buf, Index);
Index += 4;
this.nMaxSound = BitConverter.ToUInt32(Buf, Index);
Index += 4;
// read Reserved
Index += 4;
if (lpszDialogTitle > 0)
{
iEndOfString = WinCE.WinCE.findEndOfString(Buf, Index, (int)Size);
this.sDialogTitle = enc.GetString(Buf, Index, iEndOfString - Index - 2);
Index = iEndOfString;
}
if (lpszDialogText > 0)
{
iEndOfString = WinCE.WinCE.findEndOfString(Buf, Index, (int)Size);
this.sDialogText = enc.GetString(Buf, Index, iEndOfString - Index - 2);
Index = iEndOfString;
}
if (lpszSound > 0)
{
iEndOfString = WinCE.WinCE.findEndOfString(Buf, Index, (int)Size);
this.sSound = enc.GetString(Buf, Index, iEndOfString - Index - 2);
Index = iEndOfString;
}
}
}
Creating an instance of a CE_NOTIFICATION_INFO_HEADER from a byte array can now be accomplished like this:
CE_NOTIFICATION_INFO_HEADER cenih = new Notify.CE_NOTIFICATION_INFO_HEADER(Buf, Size);
And there you have it.. You now have all the pieces needed to implement notifications and scheduled events in your .Net applications. You also have all the pieces needed to create an application that manages all OS specific and user created notifications.
I wont post anything tomorrow, friday, but I'll be back monday. Have a nice weekend!
Inga kommentarer:
Skicka en kommentar