分类:
2013-12-11 22:45:23
In Taiwan, the most popular GSM radio device is TI solution. TI presents an Application control layer (ACI) idea to provide a flexible architecture. ACI is the middle layer and the application sent commands or functions to communicate with network if users want to use GSM/GPRS or other radio services.
RIL driver 的工作,就是處理從 RIL Proxy 所下來的 IO Control,轉換成相對應的 AT Command,進行應該處理的工作,並且把回應回傳給上層的 Phone application。而同時也要處理 Modem 的 unsolicited response。
Radio interface Layer is a special driver. The RIL driver services system requests for radio functionality (voice, data, SMS, etc.), and notifies the system of changes in the radio state (coverage, signal strength, incoming calls, etc.).
In order to enable your radio hardware to communicate with the Radio Interface Layer (RIL), the ODM/OEM needs to implement a hardware-specific RIL driver. RIL its work is to translate the radio function to the corresponding AT Command to Modem and get the response from Modem. It is a bridge between Microsoft AP and Radio Modem. In the Pocket PC Phone or SmartPhone point, Modem (MT) is a radio device and its work is to communicate to network.
BOOL IOControl(
DWORD dwInst,
DWORD dwIoControlCode,
LPVOID lpInBuf,
DWORD nInBufSize,
LPVOID lpOutBuf,
DWORD nOutBufSize,
LPDWORD lpBytesReturned
);
Device power state | Registry key | Description |
Full on |
D0 |
Device is on and running. It is receiving full power from the system and is delivering full functionality to the user. |
Low on |
D1 |
Device is fully functional at a lower power or performance state than D0. D1 is applicable when the device is being used, but peak performance is unnecessary and power is at a premium. |
Standby |
D2 |
Device is partially powered, with automatic wakeup on request. |
Sleep |
D3 |
Device is partially powered, with device-initiated wakeup, if available. A device in state D3 is sleeping but capable of raising the system power state on its own. It consumes only enough power to be able to do so; which must be less than or equal to the amount of power used in state D2. |
Off |
D4 |
Device has no power. A device in state D4 should not be consuming any significant power. Some peripheral busses require static terminations that intrinsically use non-zero power when a device is physically connected to the bus. A device on such a bus can still support D4. |
PowerPolicyNotify(PPN_UNATTENDEDMODE, TRUE);
TCHAR szPowerState[100]= {0};
DWORD dwPowerFlag = 0;
if (GetSystemPowerState(szPowerState, 100, &dwPowerFlag) == ERROR_SUCCESS)
{
if (dwPowerFlag & POWER_STATE_UNATTENDED) // check current power state
{
// Do something
}
}
All of the RIL functions could be broken down by groups.
Group |
Description |
Network Services | Operator selection, signal status, available operators |
Call Control | Dial, Hangup,Hold, Transfer |
Supplemental Services | Call waiting, call forwarding, call meter |
SMS | Send, receive, SMSC selection |
Data Connection | Virtual serial port, bearer service types, transparent data/online mode change |
Interface Functions | Initialization, notification registration |
GPRS Functions | Selecting GPRS profiles, attaching, context activating |
HSCSD Functions | HSCSD Functions |
Security Functions | Locking, unlocking, passwords |
Phonebook Functions | Accessing the SIM phonebooks |
SIM SMS Functions | Accessing SMS messages from the SIM |
SIM Record Access | Access individual files on the SIM |
SIM Toolkit 2.0 Support |
Microsoft handles short messages is different to phonebook. Microsoft would read the SIM card phoebook records and make the mirror records in its memory. However, Microsft privode functions to read and write the short message storage in SIM Card, but it could not make the mirror records in the memory.
RIL consists of two modules: the RIL proxy and the RIL driver.
The proxy layer is a Windows CE-based dynamic-link library (DLL) that manages callback notifications and inter-process function calls into the driver layer. CellCore modules use the RIL application programming interface (API) by linking to this proxy DLL.
#define RIL_NCLASS_FUNCRESULT (0x00000000) // @constdefine API call results
#define RIL_NCLASS_CALLCTRL (0x00010000) // @constdefine Call control notifications
#define RIL_NCLASS_MESSAGE (0x00020000) // @constdefine Messaging notifications
#define RIL_NCLASS_NETWORK (0x00040000) // @constdefine Network-related notifications
#define RIL_NCLASS_SUPSERVICE (0x00080000) // @constdefine Supplementary service notifications
#define RIL_NCLASS_PHONEBOOK (0x00100000) // @constdefine Phonebook notifications
#define RIL_NCLASS_SIMTOOLKIT (0x00200000) // @constdefine SIM Toolkit notifications
#define RIL_NCLASS_MISC (0x00400000) // @constdefine Miscellaneous notifications
#define RIL_NCLASS_RADIOSTATE (0x00800000) // @constdefine Notifications Pertaining to changes in Radio State
#define RIL_NCLASS_DEVSPECIFIC (0x80000000) // @constdefine Reserved for device specific notifications
#define RIL_NCLASS_ALL (0x00ff0000) // @constdefine All notification classes (except DevSpecifc)
[HKEY_LOCAL_MACHINE\Software\Microsoft\RIL]
"RILProxyLogNormal"=dword:1
"RILProxyLogDetail"=dword:1
Function | Description |
---|---|
RIL_Init |
Called by system during boot to start the RIL driver. This function creates the worker threads, initializes global data structures, initialize COM ports, and so on. It also launches the thread that performs radio initialization and sets the RILDrv_Present event to notify the RIL proxy that the driver was loaded and initialized successfully. |
RIL_Deinit |
Called before driver is unloaded. This function performs cleanup and clears the RILDrv_Present event to inform the RIL proxy that the driver was unloaded. |
RIL_Open |
Called by the proxy each time a client calls RIL_Initialize. This function prepares RIL for use by a new client. |
RIL_Close |
Called by the proxy each time a client calls RIL_Deinitialize. This function frees any resources that were used by a previous client. |
RIL_Read |
Reads data from the device identified by the open context. This function should return zero (0). |
RIL_Write |
Writes data to the device. This function should return zero (0). |
RIL_Seek |
Moves the data pointer in the device. This function should return -1. |
RIL_PowerUp |
Restores power to the device. This function should return a value of void. The implementation of this function is optional. |
RIL_PowerDown |
Suspends power to the device. This function should return a value of void. The implementation of this function is optional. |
switch (dwCode)
{
// RIL_GetSubscriberNumbers()
case IOCTL_RIL_GETSUBSCRIBERNUMBERS:
result = RILDrv_GetSubscriberNumbers(...);
break;
// RIL_GetOperatorList()
case IOCTL_RIL_GETOPERATORLIST:
result = RILDrv_GetOperatorList(…);
break;
}
if (!QueueCmd(PRIORITY_PORT, pHandle, "AT+CPAS\r", CMDOPT_NONE, APIID_GETLINESTATUS, ParseGetLineStatusRsp, NULL, hr)) {
hr = E_FAIL;
goto Error;
}
To enable your radio hardware to communicate with the RIL, you need to implement a hardware-specific RIL driver.
The RIL driver architecture is based on the Windows CE standard MDD/PDD driver model. It is divided into two major sections, the MDD and PDD layers. The following illustration shows the RIL architecture.
The MDD (Model Device Driver) layer is independent of the radio stack. It contains code that interfaces with the RIL Proxy and code that implements any radio stack independent features in the RIL driver.
PDD (Platform Dependent Driver) layer is radio stack dependent. It contains code specific to implementation of RIL APIs for a specific radio stack. This is the layer that must implemented by OEMs. To further ease the implementation task the PDD layer itself can be separated into a layer that contains code common to a category of radios and code for a specific radio in that category. For example, the previous illustration shows a PDD layer that is separated into code common to AT based radio stacks and code for a specific AT based radio.
Although the RIL driver is divided, into 2 major parts, the output of the build process is still a single DLL.
The Radio Interface Layer (RIL) proxy consists of a dynamic-link library (DLL) that manages callback notifications and inter-process function calls into the driver layer. CellCore modules or applications need to link to this DLL to use the RIL API. The RIL Proxy is loaded separately by each RIL client and maintains handles to the RIL driver for each client.
To use the RIL, the module only needs to use functions specified in the proxy header file (ril.h) and then link with the proxy DLL (ril.dll). Each module needs a RIL instance handle that will be used for all the RIL operations. This function RIL_Initialize() returns this handle.
When a module first registers with the RIL, it passes in two callback functions. There are two kinds of callbacks needed to be assigned as parameters of RIL_Initialize function result callback:
Function | GSM | Comments |
RIL_Dial | D +FCLASS | Dials a number |
RIL_Answer | A | Answers an incoming call |
RIL_Hangup | H | End all voice and data calls |
RIL_SendDTMF | +VTS | Sends DTMF tones |
RIL_GetCallList | +CLCC | Retrieves list of active calls and their status |
RIL_ManageCalls | +CHLD | Changes call status (hold, conference, etc) |
RIL_TransferCall | +CTFR | Explicitly transfers a call |
RIL_GetLineStatus | +CPAS | Gets line status |
RIL_SendFlash | Send CDMA hook flash |
dwCode | GSM | Comments |
RIL_NOTIFY_RING | RILRINGINFO Structure |
Incoming call |
RIL_NOTIFY_CONNECT | RILCONNECTINFO Structure |
Call connected |
RIL_NOTIFY_DISCONNECT | RIL_DISCINIT_*Constant | Call disconnected |
RIL_NOTIFY_CALLSTATECHANGED | NULL | Call state of one or more calls may have changed |
dwCode | GSM | Comments |
RIL_NOTIFY_CALLERID | ( RILREMOTEPARTYINFO * ) | The remote address of the incoming call |
RIL_NOTIFY_DIALEDID | ( RILREMOTEPARTYINFO * ) | The destination address of the outgoing call |
RIL_NOTIFY_CALLWAITING | ( RILCALLWAITINGINFO * ) | Call waiting notification |
RIL_NOTIFY_SUPSERVICEDATA | ( RILSUPSERVICEDATA * ) | Incoming USSD message |
Function | GSM | Comments |
RIL_SetCallerIDSettings | +CLIP | CallerID settings |
RIL_GetHideIDSettings | +CLIR | Hides own number from recipient |
RIL_SetHideIDStatus | +CLIR | Hides own number from recipient |
RIL_GetDialedIDSettings | +COLP | Dialed number on an outgoing call |
RIL_SetDialedIDSettings | +COLP | Dialed number on an outgoing call |
RIL_GetClosedGroupSettings | +CCUG | Closed user group settings |
RIL_AddCallForwarding | +CCFC | Add a number to the call forwarding list |
RIL_RemoveCallForwarding | +CCFC | Remove a number from the call forwarding list |
RIL_SetCallForwardStatus | +CCFC | Enable/disable call forwarding |
RIL_GetCallWaitingSettings | +CCWA | Call waiting settings |
RIL_SetCallWaitingStatus | +CCWA | Call waiting settings |
RIL_CancelSupServiceDataSession | +CUSD | Cancel a USSD session |
RIL_SendSupServiceData | +CUSD | Send a USSD message |
The process of establishing a PPP connection is started with a call to the RasDial API. RasDial causes PPP to initiate a connection through TAPI. GPRS is similar to circuit switch data call and TAPI is used but with additional DevConfig fields. GPRS data call looks like a quickly setup RAS connection.
TAPI will then call the TSP, which will in turn call RIL_Dial to initiate a data call to the specified number.
Once the call is connected, PPP will call lineGetID to get the comm. handle from the TAPI line device. The TSP will call RIL to retrieve this handle. RIL will return a handle to a virtual serial port. The virtual serial port is an integral part of RIL, and acts as the sink for data from the module. PPP will then begin reads and writes on the virtual serial port to establish the PPP connection.
Notice, For GPRS calls, Microsoft relies on the radio stack to automatically GPRS attach whenever the device registers on the network. In the boot time, MMI (AP) would send the initial string to Modem and Modem would proceed a combine attach (GSM and GPRS).
Microsoft code
[HKEY_LOCAL_MACHINE\ControlPanel\Phone]
"ShortStringExclusionList"=""
[HKEY_LOCAL_MACHINE\Security\Phone\Skin\Dialer\Portrait\Other]
"dialpadFlags"=dword:2
[HKEY_LOCAL_MACHINE\Security\Phone\Skin\Dialer\Landscape\Other]
"dialpadFlags"=dword:2
[HKEY_LOCAL_MACHINE\Security\Phone\Skin\Dialer\Square\Other]
"dialpadFlags"=dword:2
[HKEY_CURRENT_USER\ControlPanel\Phone]
"Features"=dword:0002B820 // CDMA
"Features"=dword:0206C7D8 // GSM
AT+CRSM=176,28423,0,0,9
[HKEY_LOCAL_MACHINE\Security\Phone]
"ManualDisable"=dword:1
"PreferredDisable"=dword:1
AT+CCWA=1
[HKEY_CURRENT_USER\ControlPanel\Sounds\BusyTone]
"Sound"="busytone.wav"
[HKEY_CURRENT_USER\ControlPanel\Sounds\CallWaiting]
"Sound"="waiting.wav"
[HKEY_LOCAL_MACHINE\ControlPanel\FixedDialing]
"DisableMenu"=dword:1
[HKEY_CURRENT_USER\Software\Microsoft\VMail\PhoneNumber1] -> 通常使用這個
[HKEY_CURRENT_USER\Software\Microsoft\VMail\PhoneNumber2]
[HKEY_CURRENT_USER\Software\Microsoft\VMail\DialMonitored]
[HKEY_LOCAL_MACHINE\Security\ResOver]
"55"="Please configure voicemail"
The Common PCN Handset Specification (CPHS), developed by the PCN Association, defines additional terminal and SIM functionality to the standard GSM specifications.
[HKEY_LOCAL_MACHINE\Comm\Cellular\SIM]
"UseCPHSFiles"=dword:0
For ENS to work, both an ENS-capable device and an ENS SIM are needed.
[HKEY_LOCAL_MACHINE\Comm\Cellular\RIL]如果 EONSEnabled (REG_DWORD) 設為 1 ,表示有支援 EONS,如果設為 0 表示沒有支援。
typedef struct rilnitzinfo_tagWhen the radio sends a time zone change notification (for example, CTZR:
{
DWORD cbSize;
DWORD dwParams;
DWORD dwNotificationCode;
Int TimeZoneOffsetMinutes;
SYSTEMTIME SysTime;
Int DaylightSavingOffestMinutes;
} RILNITZINFO, *LP RILNITZINFO;
[HKEY_LOCAL_MACHINE\Comm\Cellular\RIL]
"Contexts"=dword:1
[HKEY_LOCAL_MACHINE\ControlPanel\Phone]值得注意的是,這也會讓使用者可以按 END Key 中斷 data connection。
"Flags2"=dword:8
RIL 必須要分析 +CBM 的回應值,並且正確的傳到 RIL Clients(總共長度為 88 octets):
88 octets | 1-2 serial number | 3-4 message ID | data coding scheme | page num | 7-88 content payload |
The SMS Provider that accepts the incoming message performs the following steps to process the message:
If the incoming message is a multipart message, the corresponding SMS Provider begins reassembling the message when the last part of the multipart message arrives in the SMS Store. The corresponding SMS Provider uses the SMS Router Toolkit to reassemble the message.
The SMS Router uses SMS Providers to deliver, encode, decode, and receive SMS messages. SMS Providers correspond to SMS message types that are sent or received. An application can be registered to an SMS Provider, so that when an incoming SMS message matches the provider that it is registered with, the application can be invoked. Only one application can be registered to read messages from each provider. However, multiple applications can send SMS messages through a single SMS Provider.
The SMS Router has an SMS Store as a generic buffer or backup to keep copies of SMS messages that have been received. It stores SMS messages while they are being processed by the SMS Providers. The SMS Store can also be used in the event of an application failure or device shutdown. SMS messages are deleted from just the SMS Store only after an application has finished reading it.
Radio Interface Layer defines Message DCS Classes to use:
#define RIL_DCSMSGCLASS_0 (0x00000001)In the spec, short message could have several classes, class 0 (display not auto saves), class1 (ME), class 2 (SIM), class 3 (TE) or no class. However, Mobile station still could design how to save the short message.
#define RIL_DCSMSGCLASS_1 (0x00000002)
#define RIL_DCSMSGCLASS_2 (0x00000003)
#define RIL_DCSMSGCLASS_3 (0x00000004)
#define RIL_MOSMSSERVICE_CIRCUIT (0x00000001)Microsoft defines 5 const to record the parameter which users want to use CSD or GPRS to send SMS. RIL have two functions to do this thing, which is RIL_GetMOSMSService() and RIL_SetMOSMSService().
#define RIL_MOSMSSERVICE_GPRS (0x00000002)
#define RIL_MOSMSSERVICE_CIRCUITPREFERRED (0x00000004)
#define RIL_MOSMSSERVICE_GPRSPREFERRED (0x00000008)
#define RIL_MOSMSSERVICE_ALL (0x0000000f)
[HKEY_CURRENT_USER\Software\Microsoft\SMS\TextShared]
"EMSHandlerInstalled"=dword:1
[HKEY_LOCAL_MACHINE\Security\Policies\Policies]
"1033"=dword:0
相關資訊:
微軟 LTK 有 SMS/MMS 相關的測項,但是因為微軟測項本身的判斷仍然有問題,目前可以用 OEM Verify 來過這個測項。typedef struct rilsimtoolkitcmd_tag
{
DWORD cbSize; // Structure and details size
DWORD dwParams; // Bit field of valid parameters in the structure
DWORD dwId; // ID number of command
DWORD dwTag; // Command tag (with comprehension bit)
DWORD dwType; // Type of command (DISPLAY TEXT, etc.)
DWORD dwQualifier; // Command details qualifier
DWORD dwError; // Error when parsing command
DWORD dwDetailsOffset; // Offset to details command information
DWORD dwDetailsSize;
} RILSIMTOOLKITCMD;
The RILSIMTOOLKITCMD encompasses the basic SIM Toolkit information common to most commands. More specific details for the command type are contained at the details offset. Each supported command type will have a specific details structure that is needs to be created and attached in the RIL_NOTIFY_SIMTOOLKITCMD notification.[HKEY_LOCAL_MACHINE\Software\Microsoft\SIMLang]如果不顯示 SIM Contacts,可以用下列的設定:
"PurgeSimContactsWhenNoSim"=dword:0001
[HKEY_CURRENT_USER\ControlPanel\Phone\ShowSIM]
Windows Mobile powered devices enabled with 1x Evolution-Data Optimized (EVDO) wireless radio broadband should consider the overhead
cost when the Windows Mobile powered device switches between the active and dormant states.
If the Radio Interface Layer (RIL) aggressively enters the dormant state, for example, between each TCP packet, the device consumes more power and network resources. If the RIL waits too long to enter the dormant state, the device consumes power while it remains in the idle state.
For mobile operators that use Code-Division Multiple Access (CDMA) technologies, you can configure the radio and the RIL to determine when to enter the idle state through Microsoft Corporation technology. These mobile operators have specified that the tradeoff should be to go dormant when the radio has not seen data traffic for 10 to 20 seconds.
一般而言,這項特性要配合 Modem Fast Dormant 來使用。[HKEY_LOCAL_MACHINE\Software\Microsoft\RIL\LastEquipmentState]
[HKEY_LOCAL_MACHINE\Security\ResOver]下面是多國語言的寫法:
"10" = "SIM Failure"
[HKEY_LOCAL_MACHINE\Security\ResOver\0409]
"10" = "SIM Failure"
g_hlibRIL = LoadLibrary(_T("ril.dll"));在呼叫一個 RIL 函式之後,我們需要將回傳值儲存為一個全域變數,並且使用這個全域變數作為比對 command ID 之用。
if(g_hlibRIL)
{
(FARPROC&)lpRIL_Initialize = GetProcAddress( g_hlibRIL, _T("RIL_Initialize"));
if( lpRIL_Initialize==NULL )
{
goto Error;
}
(FARPROC&)lpRIL_Deinitialize = GetProcAddress(g_hlibRIL, _T("RIL_Deinitialize"));
if( lpRIL_Deinitialize==NULL )
{
goto Error;
}
}
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\DialParser\]在微軟釋出的 sample 中,有關於如何撰寫 Dial Parser 的程式。
"DLL-OEM"="DialParsExtOEM.dll"
[HKEY_LOCAL_MACHINE\Init]
或者是在 platform.dat 中設定,例如下面 VoiceCommander 的例子:{BEGIN MULTILANG}
Directory(LOC_%LANGID%_DIRWINSTMNPROG):-File("Voice Commander.lnk", "\Windows\VoiceCommander.lnk")
Directory(LOC_%LANGID%_DIRWINDOWSSTARTUP):-File("VCDaemon.lnk", "\Windows\VCDaemon.lnk")
Directory(LOC_%LANGID%_DIRWINDOWSHELP):-File("Voice Commander.lnk", "\Windows\VC.lnk")
{END MULTILANG}
在設定時最好不要寫死,否則會在發行多國語言版本時,會有問題。if(IsAPIReady(SH_SHELL))
{
//Do something
}
HANDLE processID = GetOwnerProcess();
TCHAR processName[1024];
GetModuleFileName( (HMODULE)processID, processName, 1024);
RETAILMSG(1,(TEXT("Process Name=[%s]\r\n"), processName));
void killAllCPROG()
{
TCHAR *ptchPhonePath = new TCHAR[MAX_PATH];
ZeroMemory(ptchPhonePath,sizeof(TCHAR)*MAX_PATH);
PROCESSENTRY32 pe32 = {0};
pe32.dwSize = sizeof(PROCESSENTRY32);
HANDLE hProcessShot = NULL;
TCHAR PhoneProName[] = TEXT("cprog.exe");
DWORD cprogID = 0;
HANDLE hcprogID = NULL;
hProcessShot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
BOOL running = Process32First(hProcessShot, &pe32);
//Find cprog.exe and terminate it
while(running)
{
swprintf(ptchPhonePath,TEXT("%s"),pe32.szExeFile);
if (!wcscmp(ptchPhonePath, PhoneProName))
{
cprogID = pe32.th32ProcessID;
hcprogID = OpenProcess(0,false,cprogID);
TerminateProcess(hcprogID,0);
CloseHandle(hcprogID);
}
running = Process32Next(hProcessShot, &pe32);
}
delete[] ptchPhonePath;
ptchPhonePath = NULL;
CloseToolhelp32Snapshot(hProcessShot);
}
typedef HRESULT (*SIMFUN)(HWND hwndParent, DWORD dwStyle);
HMODULE h = LoadLibrary(TEXT("simsec.dll"));
SIMFUN SIMCheck = (SIMFUN)GetProcAddress(h, TEXT("SIMSecurityUnlockPhone"));
SIMCheck(NULL, SIMSEC_STYLE_EMERGENCY_CALL | SIMSEC_STYLE_AUTO_CLOSE | SIMSEC_STYLE_SHOW_ACCEPT);
在解 dual SIM 的時候會用到,因為需要 RIL launch PIN1 code input screen。v_hevtKeyPressed = CreateEvent(NULL, FALSE, FALSE, TEXT("_KeyPress"));
SetEvent(v_hevtKeyPressed);
typedef struct _SH_BOXEX
{
DWORD cbSize; // Struct size
HWND hwndOwner; // Owner
DWORD dwStyle; // SHBEXF_* styles
UINT nTimeOut; // Timeout in ms if style includes SHBEXF_TIMED.
LPCTSTR pszTitle; // Title.
int nZOrderPri; // Z Order Priority
HINSTANCE hinst;
LPCTSTR pszTemplate;
LPCTSTR pszBannerKey;
int idrMenu;
SHB_HOOK_PROC pfnHook;
LPVOID pvUser;
LPARAM lReserved; // Reserved. Must be 0.
int nIDSelected;
HWND hwnd;
SHBEX_TYPE sbextype;
union
{
SHBEX_TEXTBOX_INFO ti; // Text box with one or two buttons
SHBEX_CLASSIC_MSGBOX_INFO cmi; // Classic Message Box info
SHBEX_CALL_ALERT_INFO cai; // Call Alert info
SHBEX_BUBBLE_INFO bi;
} info;
} SH_BOXEX, *PSH_BOXEX;
SHBEX_BUBBLE_INFO 的資料:typedef struct _SHBEX_BUBBLE_INFO
{
SHBEX_BUTTON_INFO bi; // Button info.
int iXPos; // position of the cartoon bubble
int iYPos;
int cxPos; // -1 for auto-calc
int cyPos; // -1 for auto-calc
POINT pt; // the place the bubble should stem from
DWORD dwOriginatingIcon; // Icon the bubble stems from. If specified, this info is used
// instead of pt.
DWORD dwAlign; // one of SHBOXALIGN
DWORD dwFlags; // SHBBIF_*
LPCTSTR pszContent;
HWND hwndContainer; // out: the container hwnd
COLORREF clrLeft; // For gradient fill when you have a title
COLORREF clrRight; // For gradient fill when you have a title
} SHBEX_BUBBLE_INFO;
運作這個機制,就可以秀出一個 popup window 給使用者。static const GUID CLSID_SHNAPI_Test = {0x33765136, 0x8cb9, 0x449a, {0xb0, 0x20, 0x43, 0xed, 0x40, 0xa, 0xb8, 0xfc }};
void SHNotificationExample()
{
// This code will add an SHNotification notification
SHNOTIFICATIONDATA sn = {0};
SHNOTIFICATIONDATA sn2 = {0};
sn.cbStruct = sizeof(sn);
sn.dwID = 1;
sn.npPriority = SHNP_INFORM;
sn.csDuration = 15;
sn.hicon = LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_SAMPLEICON));
sn.clsid = CLSID_SHNAPI_Test;
sn.grfFlags = 0;
sn.pszTitle = TEXT("Sample Notification");
sn.pszHTML = TEXT("This is sample html in a notification! ");
sn.rgskn[0].pszTitle = TEXT("Dismiss");
sn.rgskn[0].skc.wpCmd = 100;
//Add the notification to the tray
SHNotificationAdd(&sn);
//Put the data from an existing notification into a second SHNOTIFICATIONDATA struct
sn2.cbStruct = sizeof(sn2);
//Update the title, HTML, icon, and softkeys of the notification
sn2.pszTitle = TEXT("Updated - Sample Notification");
sn2.pszHTML = TEXT("This notification has been updated!");
sn2.hicon = LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_SAMPLEICON2));
sn2.rgskn[0].pszTitle = TEXT("Disabled");
sn2.rgskn[0].skc.wpCmd = 100;
sn2.rgskn[0].skc.grfFlags = NOTIF_SOFTKEY_FLAGS_DISABLED;
//Remove the notification from the tray
SHNotificationRemove(&CLSID_SHNAPI_Test, 1);
//Add a new notification that utilizes the MRE functionality
sn.cbStruct = sizeof(sn);
sn.dwID = 1;
sn.npPriority = SHNP_INFORM;
sn.csDuration = 15;
sn.hicon = LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_SAMPLEICON));
sn.clsid = CLSID_SHNAPI_Test;
sn.grfFlags = SHNF_STRAIGHTTOTRAY;
sn.pszTodaySK = TEXT("New Task");
sn.pszTodayExec = TEXT("\\windows\\tasks.exe");
//Add the notification to the tray
SHNotificationAdd(&sn);
//Remove the notification from the tray
SHNotificationRemove(&CLSID_SHNAPI_Test, 1);
}