Nun zum WLANNotify-ing:
Da haben sich vor gut 10 Jahren schon div. Leute
in diesem Projekt den Kopf zerbrochen und mit Event's rumgedaddelt. Hat's irgendwann dann doch geklappt ?
Nach eingehendem Studium div.
MSDN-Seiten zu dem Thema las ich sinngemäß:
".... WlanRegisterNotification funzt so lange, wie der übergebene
Handle gültig ist ...."
Aha, also:
Handle öffnen, WlanRegisterNotification aufrufen und dann entsprechend andere Funktionen hinterher ... und am Ende der selbstgemachten Routine gleich wieder den
Handle (ordnungsgemäß !) freigeben.
Da wundert's nicht, wenn nie ein (zeitlich später folgendes) Ereignis NIEMALS und der Notify-Routine auftaucht. Warten auf Godot ....
Lösung: Einfach beim Programmstart global nur einen THandle (! - hier FcHandle) holen und im gesamten Programm verwenden. Funzt tadellos hier.
Code:
function TMain.GetWlanHandle(var
Handle : THandle) : boolean;
var
res : HRESULT;
Version : DWORD;
begin
result := false;
Handle := 0;
res := WlanOpenHandle(2, nil, @Version, @
Handle); // "2" for version also XP - autom. negotiation
if res <> ERROR_SUCCESS then
begin
Memo.Lines.Add('GetWlanHandle - FAILED: ' + IntToStr(res) + ' - ' + GetErrString(res));
exit; // ... no
handle ? no function ...
end;
Memo.Lines.Add('GetWlanHandle - negotiate Version: ' + IntToStr(Version));
result:= true;
end;
Übergeben und gesetzt wird eine globale var FhClient.
Die Registrierug ist auch recht unspektakulär:
Code:
// -----------------------------------------------------------------------------
function TMain.Wlan_RegisterNotification(Mode : boolean) : HRESULT;
var
Notify : DWORD;
pProc : pointer;
begin
if NOT FIsClient then exit; // for safety !
if Mode then
begin
Notify := NDU_WLAN_NOTIFICATION_SOURCE_ALL; //_ACM
pProc := @WLanNotifyProc;
end
else
begin
Notify := NDU_WLAN_NOTIFICATION_SOURCE_NONE;
pProc := NIL;
end;
// check negotiatedVersion if needed
result := WlanRegisterNotification(FhClient, // hClientHandle [in]
NDU_WLAN_NOTIFICATION_SOURCE_ACM, // dwNotifSource [in]
//NDU_WLAN_NOTIFICATION_SOURCE_ALL,
true, // bIgnoreDuplicate [in], ignored in XP
pProc, // funcCallback [in, optional]
nil, // pCallbackContext [in, optional], always NIL
nil, // pReserved [in], always NIL
@FScanCompleteEvent //pdwPrevNotifSource [out, optional]
);
if result <> ERROR_SUCCESS then
begin
Memo.Lines.Add('RegisterNotification - FAILED: ' + IntToStr(result));
end
else
Memo.Lines.Add('RegisterNotification - OK !');
end;
Initialisiert wird das so:
Code:
procedure TMain.FormCreate(Sender: TObject);
var
res : HRESULT;
prevSource : pointer; // Register
begin
// SetUp Common
Memo.Clear;
FIF_List := TList.Create; // remind Interfaces
FIF_selected := -1; // nothing selected
FNW_List := TList.Create; // remind Networks
FNW_selected := -1; // nothing selected
FIsClient := GetWlanHandle(FhClient);;
if FIsClient then
Wlan_RegisterNotification(true);
....
end;
procedure TMain.FormDestroy(Sender: TObject);
begin
if FIsClient then
Wlan_RegisterNotification(false);
.....
end;
Und die Notify-Routine geht etwa so:
Code:
procedure WLanNotifyProc(pNotifyData : Pndu_WLAN_NOTIFICATION_DATA;
pContext : pointer); stdcall;
var
s : string;
begin
if pNotifyData^.NotificationSource = NDU_WLAN_NOTIFICATION_SOURCE_ACM then
begin
case Tndu_WLAN_NOTIFICATION_ACM(pNotifyData.NotificationCode) of
....
wlan_notification_acm_scan_complete : s := 'scan complete';
wlan_notification_acm_scan_fail : s := 'scan fail';
wlan_notification_acm_connection_start : s := 'connection start';
wlan_notification_acm_connection_complete : s := 'connection complete';
wlan_notification_acm_connection_attempt_fail : s := 'connection attempt';
....
wlan_notification_acm_disconnecting : s := 'disconnecting';
wlan_notification_acm_disconnected : s := 'disconnected';
....
end;
Main.Memo.Lines.Add('NOTIFY: ' + IntToStr(pNotifyData^.NotificationCode) + ' - ' + s);
end;
if Assigned(pNotifyData) then WlanFreeMemory(pNotifyData);
end;