![]() |
![]() |
|
|
||||||||
|
||||||||
Première partie de cet article
L’interface de Microsoft
permettant de communiquer avec un
ordinateur Windows et nos mobiles
sous Windows Mobile est :
·
ActiveSync : pour les ordinateurs dont le système d’exploitation est
XP ou en dessous (Windows
2000, Windows 98…).
·
Windows Mobile Device Center :
pour les ordinateurs dont le système d’exploitation est
Vista.
Nous allons préciser
maintenant les notifications que l’on peut recevoir d’un mobile connecté
avec ActiveSync ou
Windows Mobile Device Center.
Notifications
IDccManSink
L’interface
IDccManSink permet de recevoir des
notifications sur le PC quand un mobile est connecté ou déconnecté à
celui-ci. Cette interface est exécutée dans le thread de
Rapi.
Les notifications sont :
function
OnLogIpAddr(dwIpAddr
: DWORD): HResult; stdcall;
function
OnLogTerminated:
HResult; stdcall;
function
OnLogActive:
HResult; stdcall;
function
OnLogInactive:
HResult; stdcall;
function
OnLogAnswered:
HResult; stdcall;
function
OnLogListen:
HResult; stdcall;
function
OnLogDisconnection:
HResult; stdcall;
function
OnLogError:
HResult; stdcall;
Pour
ThemegenCE j’ai écrit un composant
(en Delphi) qui reçoit ces
notifications en temps réel, ce qui permet d’adapter les options disponibles
du programme en fonction de l’état de connexion du mobile.
Pour apprécier le temps
réel, lancer ThemeGenCE et connectez
ou déconnectez le mobile. Selon l’état, les « gros » boutons de la barre
supérieure :
·
« Lire
un Thème sur le Pocket PC ».
·
« Transfert
du Thème en cours vers le Pocket PC ».
·
« Informations
PDA si connecté ».
sont
grisés et non « cliquables » si le
mobile est déconnecté ou colorés et
fonctionnels si le mobile est connecté au PC.
Voici le composant écrit
en Delphi mais certainement
facilement adaptable pour d’autres langages. Je me suis servi des données de
MSDN pour le concevoir (http://msdn.microsoft.com/en-us/library/aa912022.aspx).
Le module de Microsoft
qui a servi de base à la conception du composant :
/*++
Copyright (c)
Microsoft Corporation. All rights reserved.
Module Name:
dccole2.h
Abstract:
This file
defines OLE interface to the DCCMAN module (Desktop Only).
It includes the
old interfaces from dccole.h and contains
a new
IDCCManSink2 interface for IPv6 support.
Environment:
User Mode -
Win32
--*/
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus
*/
//
{A7B88840-A812-11cf-8011-00A0C90A8F78}
DEFINE_GUID(IID_IDccManSink,
0xa7b88840, 0xa812,
0x11cf, 0x80, 0x11, 0x0, 0xa0, 0xc9, 0xa, 0x8f, 0x78);
//
{A7B88841-A812-11cf-8011-00A0C90A8F78}
DEFINE_GUID(IID_IDccMan,
0xa7b88841, 0xa812,
0x11cf, 0x80, 0x11, 0x0, 0xa0, 0xc9, 0xa, 0x8f, 0x78);
//
{499C0C20-A766-11cf-8011-00A0C90A8F78}
DEFINE_GUID(CLSID_DccMan,
0x499c0c20, 0xa766,
0x11cf, 0x80, 0x11, 0x0, 0xa0, 0xc9, 0xa, 0x8f, 0x78);
//
{1317003A-9A62-4040-98F1-9CE9EFD8298B}
DEFINE_GUID(IID_IDccManSink2,
0x1317003a, 0x9a62,
0x4040, 0x98, 0xf1, 0x9c, 0xe9, 0xef, 0xd8, 0x29, 0x8b);
#ifndef _DCCOLEH_
#define _DCCOLEH_
#undef
INTERFACE
#define INTERFACE
IDccManSink
DECLARE_INTERFACE_
(IDccManSink, IUnknown)
{
// These methods corespond to GW_LOG messages generated by the
Win95 DCC
STDMETHOD(OnLogIpAddr) (THIS_ DWORD dwIpAddr) PURE;
STDMETHOD(OnLogTerminated) (THIS) PURE;
STDMETHOD(OnLogActive) (THIS) PURE;
STDMETHOD(OnLogInactive) (THIS) PURE;
STDMETHOD(OnLogAnswered) (THIS) PURE;
STDMETHOD(OnLogListen) (THIS) PURE;
STDMETHOD(OnLogDisconnection) (THIS) PURE;
STDMETHOD(OnLogError) (THIS) PURE;
};
typedef IDccManSink
*LPDCCMANSINK;
#undef
INTERFACE
#define INTERFACE
IDccMan
DECLARE_INTERFACE_
(IDccMan, IUnknown)
{
STDMETHOD(Advise) (THIS_
IN
IDccManSink * pDccSink,
// The advise sink that is requesting notification
OUT DWORD * pdwContext
// Identifies the context for future calls to the Unadvise method
) PURE;
STDMETHOD(Unadvise) (THIS_
DWORD dwContext
// As returned by Advise()
) PURE;
STDMETHOD(ShowCommSettings) (THIS) PURE;
// Displays the Communication Property Sheet on the screen
// If a connection is active, the sheet is in read-only mode
STDMETHOD(AutoconnectEnable) (THIS) PURE;
STDMETHOD(AutoconnectDisable) (THIS) PURE;
STDMETHOD(ConnectNow) (THIS) PURE;
// Active only when Autoconnect is Disabled
STDMETHOD(DisconnectNow) (THIS) PURE;
// Active only when Autoconnect is Disabled
STDMETHOD(SetIconDataTransferring) (THIS) PURE;
STDMETHOD(SetIconNoDataTransferring) (THIS) PURE;
STDMETHOD(SetIconError) (THIS) PURE;
};
typedef IDccMan
*LPDCCMAN;
#endif /* end, ifdef
_DCCOLEH_ */
//================ New
Sink Interface for IPv6 support ========================
#ifndef _DCCOLE2H_
#define _DCCOLE2H_
#include <winsock2.h>
#undef
INTERFACE
#define INTERFACE
IDccManSink2
DECLARE_INTERFACE_
(IDccManSink2, IDccManSink)
{
STDMETHOD(OnLogIpAddrEx) (THIS_ const SOCKADDR_STORAGE* pIpAddr) PURE;
};
typedef IDccManSink2
*LPDCCMANSINK2;
#endif /*_DCCOLE2H_*/
#ifdef __cplusplus
}
#endif
/* __cplusplus */
Et maintenant le
composant Delphi :
(*
-------------------------------------------
\\\|///
\\ - -
//
( @ @
)
-------oOOo-(_)-oOOo----------
Copyright (c)Benoît Thonnart
2005
AutoSink
-----------------Oooo---------
oooO (
)
( )
) /
\ ( (_/
\_)
---------------------------------------------*)
unit AutoSink;
interface
uses
Windows,
Classes, ActiveX, SysUtils, ComObj(*, Dialogs*);
const
CLSID_DccMan :
TGUID = '{499C0C20-A766-11cf-8011-00A0C90A8F78}';
IID_IDccMan
: TGUID = '{A7B88841-A812-11cf-8011-00A0C90A8F78}';
IID_IDccManSink : TGUID = '{A7B88840-A812-11cf-8011-00A0C90A8F78}';
type
IDccManSink = interface(IUnknown)
['{A7B88840-A812-11cf-8011-00A0C90A8F78}']
function OnLogIpAddr(dwIpAddr : DWORD): HResult; stdcall;
function OnLogTerminated: HResult; stdcall;
function OnLogActive: HResult; stdcall;
function OnLogInactive: HResult; stdcall;
function OnLogAnswered: HResult; stdcall;
function OnLogListen: HResult; stdcall;
function OnLogDisconnection: HResult; stdcall;
function OnLogError: HResult; stdcall;
end;
LPDCCMANSINK = ^IDccManSink;
IDccMan =
interface(IUnknown)
['{A7B88841-A812-11cf-8011-00A0C90A8F78}']
function Advise(pDccSink : LPDCCMANSINK; var pdwContext : DWORD):
HResult; stdcall;
function Unadvise(dwContext : DWORD): HResult; stdcall;
function ShowCommSettings: HResult; stdcall;
function AutoconnectEnable: HResult; stdcall;
function AutoconnectDisable: HResult; stdcall;
function ConnectNow: HResult; stdcall;
function DisconnectNow: HResult; stdcall;
function SetIconDataTransferring: HResult; stdcall;
function SetIconNoDataTransferring: HResult; stdcall;
function SetIconError: HResult; stdcall;
end;
//LPDCCMAN
= ^IDccMan;
{$M+}
{
Déclaration forward pour FOwner }
TDccMan =
class;
{
Déclaration TDccEventSink }
TDccEventSink = class(TInterfacedObject, IUnknown, IDccManSink)
private
FNbRef : integer;
FOnLogEtat : string;
FOnLogIndex : integer;
FOwner : TDccMan;
public
{ IUnknown }
function QueryInterface(const IID: TGUID; out Obj): HRESULT;
stdcall;
function _AddRef: Integer; stdcall;
function _Release: Integer; stdcall;
{ IDccManSink}
function OnLogIpAddr(dwIpAddr : DWORD): HResult; stdcall;
function OnLogTerminated: HResult; stdcall;
function OnLogActive: HResult; stdcall;
function OnLogInactive: HResult; stdcall;
function OnLogAnswered: HResult; stdcall;
function OnLogListen: HResult; stdcall;
function OnLogDisconnection: HResult; stdcall;
function OnLogError: HResult; stdcall;
constructor Create(AOwner : TDccMan);
destructor Destroy; override;
function RehercheInterface(var p : LPDCCMANSINK) : HResult;
property OnLogEtat : string read FOnLogEtat stored '';
property OnLogIndex : integer read FOnLogIndex stored - 1;
published
//
end;
//pDccEventSink = ^TDccEventSink;
{
Déclaration TDccMan }
TDccMan =
class
private
FIDccMan : IDccMan;
FdwContext : DWORD;
FDccSync : TDccEventSink;
FpIMS : LPDCCMANSINK;
FComLib : boolean;
FQI : boolean;
FAdvise : boolean;
FOnChange : TNotifyEvent;
procedure DoChange(Sender : TObject);
public
constructor Create;
destructor Destroy; override;
procedure Advise;
procedure Unadvise;
procedure ShowCommSettings;
function LitEtat : string;
function LitIndex : integer;
property ComLibOk : boolean read FComLib stored false;
property InterfaceOk : boolean read FQI stored false;
property NotificationOk : boolean read FAdvise stored false;
property Etat : string read LitEtat stored '';
property IndexOnLog : integer read LitIndex stored - 1;
published
property OnChange : TNotifyEvent read FOnChange write FOnChange;
end;
implementation
{ TDccMan implementation }
constructor
TDccMan.Create;
var
hr :
HRESULT;
begin
inherited
Create;
CoInitialize(nil);
FComLib :=
false;
FQI :=
false;
FAdvise :=
false;
hr :=
CoCreateInstance(CLSID_DccMan, nil, CLSCTX_INPROC_SERVER or
CLSCTX_LOCAL_SERVER, IID_IDccMan, FIDccMan);
if
SUCCEEDED(hr) then
begin
FComLib := true;
FDccSync := TDccEventSink.Create(Self);
hr := FDccSync.RehercheInterface(FpIMS);
if SUCCEEDED(hr) then FQI := true;
end;
end;
destructor
TDccMan.Destroy;
begin
Unadvise;
if
Assigned(FDccSync) then FDccSync.Free;
CoUninitialize;
inherited
Destroy;
end;
procedure
TDccMan.Advise;
var
hr :
HRESULT;
begin
//
apparemment on peut cumuler les appels
// si déjà
Advise redonne l'état actuel (actif ou autre)
// peut
être utile, mais le contexte a changé !!
if FQI and
not FAdvise then
begin
hr := FIDccMan.Advise(FpIMS, FdwContext);
if SUCCEEDED(hr) then FAdvise := true;
end;
end;
procedure
TDccMan.Unadvise;
begin
if FAdvise
then
begin
FIDccMan.Unadvise(FdwContext);
FAdvise := false;
end;
end;
procedure
TDccMan.ShowCommSettings;
begin
if FComLib
then FIDccMan.ShowCommSettings;
end;
function
TDccMan.LitEtat
: string;
begin
if
Assigned(FDccSync) then Result := FDccSync.FOnLogEtat
else
Result := '';
end;
function
TDccMan.LitIndex
: integer;
begin
if
Assigned(FDccSync) then Result := FDccSync.FOnLogIndex
else
Result := - 1;
end;
procedure
TDccMan.DoChange(Sender
: TObject);
begin
if
Assigned(FOnChange) then FOnChange(Self);
end;
{ TDccEventSink implementation }
constructor
TDccEventSink.Create(AOwner
: TDccMan);
begin
inherited
Create;
FNbRef :=
0;
FOwner :=
AOwner;
end;
destructor
TDccEventSink.Destroy;
begin
_Release;
inherited
Destroy;
end;
function
TDccEventSink.QueryInterface(const
IID: TGUID; out Obj): HRESULT;
begin
Result :=
E_NOINTERFACE;
if
GetInterface(IID, Obj) then Result := S_OK;
end;
function
TDccEventSink.RehercheInterface(var
p : LPDCCMANSINK) : HResult;
begin
Result :=
QueryInterface(IID_IDccManSink, p);
end;
function
TDccEventSink._AddRef:
Integer;
begin
InterLockedIncrement(FNbRef);
{
FOnLogIndex := 200;
FOnLogEtat
:= Format('AddRef %d', [FNbRef]);
FOwner.DoChange(Self); }
Result :=
2;
end;
function
TDccEventSink._Release:
Integer;
begin
InterLockedDecrement(FNbRef);
{
FOnLogIndex := 100;
FOnLogEtat
:= Format('Release %d', [FNbRef]);
FOwner.DoChange(Self); }
Result :=
1;
end;
function
TDccEventSink.OnLogIpAddr(dwIpAddr
: DWORD): HResult;
begin
FOnLogIndex := 1;
FOnLogEtat
:= Format('IP Adress : %d.%d.%d.%d',
[dwIpAddr and $FF,
(dwIpAddr and $FF00) shr 8,
(dwIpAddr and $FF0000) shr 16,
dwIpAddr shr 24]);
FOwner.DoChange(Self);
Result :=
NO_ERROR;
end;
function
TDccEventSink.OnLogTerminated:
HResult;
begin
FOnLogIndex := 2;
FOnLogEtat
:= 'Closed';
FOwner.DoChange(Self);
Result :=
NO_ERROR;
end;
function
TDccEventSink.OnLogActive:
HResult;
begin
FOnLogIndex := 3;
FOnLogEtat
:= 'Active';
FOwner.DoChange(Self);
Result :=
NO_ERROR;
end;
function
TDccEventSink.OnLogInActive:
HResult;
begin
FOnLogIndex := 4;
FOnLogEtat
:= 'Inactive';
FOwner.DoChange(Self);
Result :=
NO_ERROR;
end;
function
TDccEventSink.OnLogAnswered:
HResult;
begin