The ActiveSync Manager provides the desktop with two different ways of receiving notifications when a Pocket PC device is either connected or disconnected from it:
The desktop registry. You can use the registry on a desktop machine that has ActiveSync installed on it to set up which applications are to be run when a device is connected or disconnected.
COM-based notification. You can implement a COM object that can be registered with ActiveSync; it will receive notifications when various device connection events occur.
Although using the registry to launch an application is the easiest way to handle a connection notification, no other information about the connection event is provided to you. You should create a COM object notification if more details are required.
To have an application launch when a connection is made with the desktop, you need to create a new string value underneath the following registry entry:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows CE Services\ AutoStartOnConnect
It is recommended that the key name for the new string value should uniquely represent the application you are launching, along with the company name. The data value should point to the full path and name, and include any command-line arguments for the application you want to launch. If you include any arguments, you must also wrap the full path in double quotes.
For example, to launch the application devicebackup.exe when a connection is established, the registry will look like the following:
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows CE Services\AutoStartOnConnect] "BionicFrogDeviceBackup"="\"C:\\Program Files\\BionicFrog\\devicebackup.exe\""
To have an application launch when a device is disconnected from the desktop, you can place a new registry string value underneath the following key:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows CE Services\ AutoStartOnDisconnect
Like the AutoStartOnConnect key, the disconnect registry key also takes a string value with the application path in order to run.
Two interfaces are used to perform notification of connection events when using COM:
The IDccMan interface is already implemented by ActiveSync, and is used to register your IDccManSink object. It provides your application with some control of the communication aspects of ActiveSync.
The IDccManSink interface is what you are required to implement in order to receive notifications from IDccMan. The object's functions are called by ActiveSync whenever connection events occur.
The interfaces that you will use to work with the notification objects are prototyped in the dccole.h header file.
The IDccManSink interface is the only interface that your application needs to implement in order to receive notifications from the ActiveSync Manager. Table 9.27 describes the methods supported by IDccManSink that are called during the various states of a device's connection to the desktop.
All of the methods that IDccManSink supports are pretty self-explanatory?each is called by IDccMan whenever a particular event takes place. The only method that has any useful additional information is the IDccManSink::OnLogIpAddr(DWORD dwIpAddr) method, which will pass you the connecting device's IP address when a communications link has been established.
Method | Description |
---|---|
OnLogActive() | Notification when a connection is established between a device and ActiveSync |
OnLogAnswered() | Notification when ActiveSync has detected a device |
OnLogDisconnection() | Notification when a connection has been terminated between the device and ActiveSync |
OnLogError() | Notification when ActiveSync has failed to start communications between the desktop and the device |
OnLogInActive() | Notification when ActiveSync is in a disconnected state |
OnLogIpAddr() | Notification when an IP address has been established for communications between the device and the desktop |
OnLogListen() | Notification that a connection is waiting to be established |
OnLogTerminated() | Notification when ActiveSync has been shut down |
The IDccMan interface is implemented by the ActiveSync Manager, and enables you to register your own IDccManSink interface to receive notifications from it. Table 9.28 describes the methods that are implemented by the IDccMan object.
Method | Description |
---|---|
Advise() | Registers an IDccManSink object for notification messages |
ShowCommSettings() | Shows the ActiveSync Communications Settings dialog box |
Unadvise() | Prevents an IDccManSink object from receiving any further notification messages |
To register a new notification object with ActiveSync, you must pass a pointer to the IDccManSink interface that you implemented to the IDccMan::Advise() function. It is defined as follows:
HRESULT IDccMan::Advise(IDccManSink *pDccSink, DWORD *pdwContext);
The first parameter is a pointer to the notification object that will be used by IDccMan to send notifications to. The pdwContext parameter will be filled in with a DWORD value that uniquely identifies the object you passed into pDccSink. The value that you are returned must be used to call the IDccMan::Unadvise() function when you are finished receiving notifications.
You can also tell ActiveSync to display the Communication Configuration dialog box by using the following function:
HRESULT IDccMan::ShowCommSettings();
The only other function that IDccMan provides is what you use to let ActiveSync know you are no longer interested in receiving notification. The IDccMan::Unadvise() function takes a single parameter, which is the context value that was returned from your call to IDccMan::Advise(). The function is defined as follows:
HRESULT IDccMan::Unadvise(DWORD dwContext);
The process for using COM-based notification is relatively simple. Your application needs to first call CoInitializeEx() and CoCreateInstance() in order to get a pointer to the IDccMan object that ActiveSync has implemented.
The code for getting the IDccMan interface pointer is as follows:
// Get the IDccMan Interface IDccMan *pDccMan = NULL; HRESULT hr = S_OK; hr = CoCreateInstance(CLSID_DccMan, NULL, CLSCTX_SERVER, IID_IDccMan, (LPVOID *)&pDccMan); if(FAILED(hr)) return 0;
Once you have received the pointer, you can call into the IDccMan::Advise() function to register the IDccManSink you have implemented in your application.
For example, you can register your object for notification as follows:
// Hook up the notification DWORD dwContext = 0; hr = pDccMan->Advise(pDccManSink, &dwContext);
Once the application is ready to stop receiving notifications, remember to call the IDccMan::UnAdvise() function, as well as clean up the other COM objects you used:
// Clean up if(pDccMan) { pDccMan->Unadvise(dwContext); pDccMan->Release(); }
The implementation for a basic IDccManSink interface is shown in the following example code:
// CeNotify.h #include <windows.h> #include <initguid.h> #include <dccole.h> #include "resource.h" INT_PTR CALLBACK DlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); // IDccManSink class CDccSink:public IDccManSink { private: long m_lRef; public: CDccSink(); ~CDccSink(); // IUnknown STDMETHODIMP QueryInterface(REFIID riid, LPVOID *ppv); STDMETHODIMP_(ULONG) AddRef(); STDMETHODIMP_(ULONG) Release(); // IDccManSink STDMETHODIMP OnLogIpAddr(DWORD dwIpAddr); STDMETHODIMP OnLogTerminated(); STDMETHODIMP OnLogActive(); STDMETHODIMP OnLogInactive(); STDMETHODIMP OnLogAnswered(); STDMETHODIMP OnLogListen(); STDMETHODIMP OnLogDisconnection(); STDMETHODIMP OnLogError(); }; ///////////////////////////////////////////////// // CeNotify.cpp #include "cenotify.h" int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd) { // Initalize COM CoInitialize(NULL); // Get the IDccMan interface IDccMan *pDccMan = NULL; HRESULT hr = S_OK; hr = CoCreateInstance(CLSID_DccMan, NULL, CLSCTX_SERVER, IID_IDccMan, (LPVOID *)&pDccMan); if(FAILED(hr)) return 0; // Get an instance of our IDccManSink CDccSink *pDccSink = new CDccSink(); IDccManSink *pDccManSink = NULL; hr = pDccSink->QueryInterface(IID_IDccManSink, (void **)&pDccManSink); if(FAILED(hr)) { pDccMan->Release(); return 0; } // Hook up the notification DWORD dwContext = 0; hr = pDccMan->Advise(pDccManSink, &dwContext); // Do something while getting notifications DialogBox(hInstance, MAKEINTRESOURCE(IDD_DIALOG), NULL, (DLGPROC)DlgProc); // Clean up if(pDccMan) { pDccMan->Unadvise(dwContext); pDccMan->Release(); } return 0; } INT_PTR CALLBACK DlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg) { case WM_COMMAND: switch (LOWORD(wParam)) { case IDOK: case IDCANCEL: EndDialog(hwndDlg, wParam); return TRUE; } } return FALSE; } // DccSink object CDccSink::CDccSink() { m_lRef = 1; return; } CDccSink::~CDccSink() { return; } // IDccManSink's IUnknown interface STDMETHODIMP CDccSink::QueryInterface(REFIID riid, LPVOID *ppv) { if(IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_IDccManSink)) { *ppv = (IDccManSink *)this; AddRef(); return NO_ERROR; } *ppv = NULL; return E_NOINTERFACE; } STDMETHODIMP_(ULONG) CDccSink::AddRef() { return (ULONG)InterlockedIncrement(&m_lRef); } STDMETHODIMP_(ULONG) CDccSink::Release() { ULONG ulCount = (ULONG)InterlockedDecrement(&m_lRef); if(ulCount == 0) delete this; return ulCount; } // IDccManSink implementation STDMETHODIMP CDccSink::OnLogIpAddr(DWORD dwIpAddr) { OutputDebugString(TEXT("Received a new IP Address\r\n")); return NO_ERROR; } STDMETHODIMP CDccSink::OnLogTerminated() { OutputDebugString(TEXT("On Log Terminated\r\n")); return NO_ERROR; } STDMETHODIMP CDccSink::OnLogActive() { OutputDebugString(TEXT("On Log Active\r\n")); return NO_ERROR; } STDMETHODIMP CDccSink::OnLogInactive() { OutputDebugString(TEXT("On Log InActive\r\n")); return NO_ERROR; } STDMETHODIMP CDccSink::OnLogAnswered() { OutputDebugString(TEXT("On Log Answered\r\n")); return NO_ERROR; } STDMETHODIMP CDccSink::OnLogListen() { OutputDebugString(TEXT("On Log Listen\r\n")); return NO_ERROR; } STDMETHODIMP CDccSink::OnLogDisconnection() { OutputDebugString(TEXT("On Log Disconnection\r\n")); return NO_ERROR; } STDMETHODIMP CDccSink::OnLogError() { OutputDebugString(TEXT("On Log Error\r\n")); return NO_ERROR;