You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
636 lines
16 KiB
636 lines
16 KiB
/*++
|
|
|
|
Copyright (c) 1991-1993 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
connify.cxx
|
|
|
|
Abstract:
|
|
|
|
Contains code used to notify all DLLs interested in notifiable MPR
|
|
Events. Currently only connection information results in
|
|
notification.
|
|
|
|
Author:
|
|
|
|
Dan Lafferty (danl) 14-Dec-1993
|
|
|
|
Environment:
|
|
|
|
User Mode -Win32
|
|
|
|
Revision History:
|
|
|
|
14-Dec-1993 danl
|
|
created
|
|
|
|
05-May-1999 jschwart
|
|
Make provider addition/removal dynamic
|
|
|
|
--*/
|
|
|
|
//
|
|
// INCLUDES
|
|
//
|
|
|
|
#include "precomp.hxx"
|
|
#include "connify.h" // MprAddConnectNotify
|
|
|
|
|
|
//===================
|
|
// TYPEDEFs
|
|
//===================
|
|
typedef struct _NOTIFYEE {
|
|
PF_AddConnectNotify PF_AddConnectNotify;
|
|
PF_CancelConnectNotify PF_CancelConnectNotify;
|
|
HINSTANCE DllHandle;
|
|
}NOTIFYEE, *LPNOTIFYEE;
|
|
|
|
//===================
|
|
// DEFINES
|
|
//===================
|
|
#define NOTIFYEE_ROOT TEXT("system\\CurrentControlSet\\Control\\NetworkProvider\\Notifyees")
|
|
|
|
|
|
//===================
|
|
// GLOBALs
|
|
//===================
|
|
//
|
|
// A pointer to an array of NOTIFYEE structures.
|
|
// These are only modified by MprConnectNotifyInif.
|
|
// The MprInitCritSec is obtained prior to calling
|
|
// MprConnectNotifyInit.
|
|
//
|
|
LPNOTIFYEE NotifyList = NULL;
|
|
DWORD GlobalNumNotifyees = 0;
|
|
|
|
|
|
|
|
DWORD
|
|
MprConnectNotifyInit(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function does the following:
|
|
1) Look in the registry to determine which DLLs want to be notified of
|
|
Connection Events.
|
|
2) Load the Notifiee DLLs.
|
|
3) Obtain the entry points for the notify functions.
|
|
4) Create a list of all the Notifiee Information.
|
|
|
|
Arguments:
|
|
|
|
NONE
|
|
|
|
Return Value:
|
|
|
|
WN_SUCCESS
|
|
|
|
|
|
--*/
|
|
{
|
|
HKEY notifyeeRootKey;
|
|
DWORD status;
|
|
DWORD numSubKeys;
|
|
DWORD cchMaxSubKey;
|
|
DWORD numValues;
|
|
DWORD cchMaxValueName;
|
|
DWORD type;
|
|
DWORD bufSize;
|
|
TCHAR dllPath[MAX_PATH];
|
|
TCHAR buffer[MAX_PATH];
|
|
LPTSTR expandedPath=NULL;
|
|
DWORD nameSize;
|
|
HINSTANCE hLib=NULL;
|
|
DWORD i;
|
|
DWORD numReqd;
|
|
LPNOTIFYEE NotifyEntry;
|
|
|
|
//
|
|
// Read the Registry Information for Notifiees.
|
|
// If the key doesn't exist, then there is no one to notify.
|
|
//
|
|
if (!MprOpenKey (
|
|
HKEY_LOCAL_MACHINE, // hKey
|
|
NOTIFYEE_ROOT, // lpSubKey
|
|
¬ifyeeRootKey, // Newly Opened Key Handle
|
|
DA_READ)) { // Desired Access
|
|
|
|
MPR_LOG0(CNOTIFY,"MprConnectInfoInit: NOTIFYEE_ROOT doesen't exist\n");
|
|
return(WN_SUCCESS);
|
|
}
|
|
|
|
//
|
|
// GetKeyInfo (find out how many values)
|
|
//
|
|
|
|
if (!MprGetKeyInfo (
|
|
notifyeeRootKey,
|
|
NULL,
|
|
&numSubKeys,
|
|
&cchMaxSubKey,
|
|
&numValues,
|
|
&cchMaxValueName)) {
|
|
|
|
RegCloseKey( notifyeeRootKey );
|
|
MPR_LOG0(CNOTIFY,"MprConnectInfoInit: Couldn't get key info\n");
|
|
return(WN_SUCCESS);
|
|
}
|
|
MPR_LOG1(CNOTIFY,"MprConnectInfoInit: GlobalNumNotifyees = %d\n",numValues);
|
|
|
|
//
|
|
// Allocate space for that many notifyees.
|
|
//
|
|
if (numValues == 0) {
|
|
RegCloseKey( notifyeeRootKey );
|
|
return(WN_SUCCESS);
|
|
}
|
|
|
|
NotifyList = (LPNOTIFYEE) LocalAlloc(LPTR,numValues * sizeof(NOTIFYEE));
|
|
if (NotifyList == NULL) {
|
|
RegCloseKey( notifyeeRootKey );
|
|
return(GetLastError());
|
|
}
|
|
|
|
NotifyEntry = NotifyList;
|
|
//
|
|
// Load the Notifyees and get their entry points.
|
|
//
|
|
for (i=0; i<numValues; i++) {
|
|
bufSize = MAX_PATH * sizeof (TCHAR);
|
|
nameSize = MAX_PATH;
|
|
expandedPath = NULL;
|
|
|
|
status = RegEnumValue(
|
|
notifyeeRootKey,
|
|
i,
|
|
buffer,
|
|
&nameSize,
|
|
NULL,
|
|
&type,
|
|
(LPBYTE)dllPath,
|
|
&bufSize);
|
|
|
|
if (status != NO_ERROR) {
|
|
MPR_LOG0(CNOTIFY,"MprConnectInfoInit: RegEnumValue failure\n");
|
|
}
|
|
else {
|
|
switch (type) {
|
|
case REG_EXPAND_SZ:
|
|
numReqd = ExpandEnvironmentStrings(dllPath,buffer,MAX_PATH);
|
|
if (numReqd > MAX_PATH) {
|
|
expandedPath = (LPTSTR) LocalAlloc(LMEM_FIXED,numReqd*sizeof(TCHAR) );
|
|
if (expandedPath == NULL) {
|
|
//
|
|
// We can't expand the string, so we skip this notifyee
|
|
// and go onto the next.
|
|
//
|
|
status = GetLastError();
|
|
break; // Leave the switch and cleanup this notifyee
|
|
}
|
|
numReqd = ExpandEnvironmentStrings(dllPath,expandedPath,numReqd);
|
|
if (numReqd > MAX_PATH) {
|
|
MPR_LOG0(CNOTIFY,"MprConnectNotifyInit: Couldn't Expand Path\n");
|
|
status = ERROR_BAD_LENGTH;
|
|
break; // Leave the switch and cleanup this notifyee
|
|
}
|
|
}
|
|
else {
|
|
expandedPath = buffer;
|
|
}
|
|
|
|
// Fall thru to the REG_SZ case....
|
|
|
|
case REG_SZ:
|
|
if (expandedPath == NULL) {
|
|
expandedPath = dllPath;
|
|
}
|
|
//
|
|
// Load the DLL
|
|
//
|
|
hLib = LoadLibraryEx(expandedPath,
|
|
NULL,
|
|
LOAD_WITH_ALTERED_SEARCH_PATH);
|
|
if (hLib == NULL) {
|
|
status = GetLastError();
|
|
MPR_LOG2(CNOTIFY,"MprConnectInfoInit:LoadLibraryEx for %ws failed %d\n",
|
|
expandedPath, status);
|
|
|
|
break; // Leave the switch and cleanup this notifyee
|
|
}
|
|
|
|
//
|
|
// Get the Entry Points from the DLL.
|
|
//
|
|
NotifyEntry->PF_AddConnectNotify =
|
|
(PF_AddConnectNotify)GetProcAddress(hLib,"AddConnectNotify");
|
|
NotifyEntry->PF_CancelConnectNotify =
|
|
(PF_CancelConnectNotify)GetProcAddress(hLib,"CancelConnectNotify");
|
|
|
|
//
|
|
// If and Only If both functions are supported, then increment
|
|
// the NotifyList.
|
|
//
|
|
if ((NotifyEntry->PF_AddConnectNotify != NULL) &&
|
|
(NotifyEntry->PF_CancelConnectNotify != NULL)) {
|
|
NotifyEntry->DllHandle = hLib;
|
|
NotifyEntry++;
|
|
GlobalNumNotifyees++;
|
|
MPR_LOG1(CNOTIFY,"MprConnectInfoInit: Item added to "
|
|
"notify list %d\n",GlobalNumNotifyees);
|
|
}
|
|
else {
|
|
FreeLibrary (hLib);
|
|
hLib = NULL;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Cleanup resources for this notifyee
|
|
//
|
|
if ((expandedPath != NULL) &&
|
|
(expandedPath != dllPath) &&
|
|
(expandedPath != buffer)) {
|
|
LocalFree(expandedPath);
|
|
}
|
|
|
|
} // End for(Each Notifyee)
|
|
|
|
if (GlobalNumNotifyees == 0) {
|
|
if (NotifyList != NULL) {
|
|
LocalFree(NotifyList);
|
|
NotifyList = NULL;
|
|
}
|
|
}
|
|
|
|
RegCloseKey(notifyeeRootKey);
|
|
return(WN_SUCCESS);
|
|
}
|
|
|
|
VOID
|
|
MprCleanupNotifyInfo(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
DWORD i;
|
|
|
|
ASSERT_INITIALIZED(NOTIFIEE);
|
|
|
|
for (i=0; i<GlobalNumNotifyees; i++ ) {
|
|
FreeLibrary(NotifyList[i].DllHandle);
|
|
}
|
|
LocalFree(NotifyList);
|
|
return;
|
|
}
|
|
|
|
|
|
PVOID
|
|
MprAllocConnectContext(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
ASSERT_INITIALIZED(NOTIFIEE);
|
|
|
|
if (GlobalNumNotifyees == 0) {
|
|
return(NULL);
|
|
}
|
|
MPR_LOG1(CNOTIFY,"In MprAllocConnectContext. Allocating for %d notifyees\n",
|
|
GlobalNumNotifyees);
|
|
|
|
return(PVOID)(LocalAlloc(LPTR,sizeof(PVOID) * GlobalNumNotifyees));
|
|
}
|
|
|
|
|
|
VOID
|
|
MprFreeConnectContext(
|
|
PVOID ConnectContext
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
MPR_LOG0(CNOTIFY,"In MprFreeConnectContext\n");
|
|
LocalFree(ConnectContext);
|
|
}
|
|
|
|
|
|
DWORD
|
|
MprAddConnectNotify(
|
|
LPNOTIFYINFO lpNotifyInfo,
|
|
LPNOTIFYADD lpAddInfo
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function calls all the Notifyees if an add connection event.
|
|
|
|
Arguments:
|
|
|
|
lpNotifyInfo -
|
|
lpAddInfo -
|
|
|
|
Return Value:
|
|
|
|
If any of the notifyees returns WN_CANCEL, the notification is immediately
|
|
aborted and the WN_CANCEL is returned from the caller.
|
|
Aside from that error, if WN_RETRY is returned from any notifyee, then
|
|
WN_RETRY is returned to the caller. Otherwise, the last error is returned.
|
|
If all notifyees return WN_SUCCESS, then the last error will be WN_SUCCESS.
|
|
|
|
--*/
|
|
{
|
|
DWORD i;
|
|
DWORD status;
|
|
DWORD lastError=WN_SUCCESS;
|
|
BOOL retryFlag=FALSE;
|
|
DWORD numNotifyees = GlobalNumNotifyees;
|
|
PVOID *ContextInfo;
|
|
LPNOTIFYEE NotifyEntry=NotifyList;
|
|
|
|
MPR_LOG0(CNOTIFY,"In MprAddConnectNotify\n");
|
|
|
|
ASSERT_INITIALIZED(NOTIFIEE);
|
|
|
|
//
|
|
// Save away the pointer to the array of context information.
|
|
//
|
|
ContextInfo = (PVOID *) lpNotifyInfo->lpContext;
|
|
|
|
for (i=0; i<numNotifyees; i++,NotifyEntry++ )
|
|
{
|
|
if (lpNotifyInfo->dwNotifyStatus == NOTIFY_POST)
|
|
{
|
|
if (ContextInfo && ContextInfo[i] != NULL)
|
|
{
|
|
lpNotifyInfo->lpContext = ContextInfo[i];
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Don't notify if it is a POST notification, and there
|
|
// is no context saved. Here we go directly to the next
|
|
// notifyee (or out of the for loop).
|
|
//
|
|
continue;
|
|
}
|
|
}
|
|
|
|
status = NotifyEntry->PF_AddConnectNotify(lpNotifyInfo,lpAddInfo);
|
|
|
|
switch (status) {
|
|
case WN_SUCCESS:
|
|
MPR_LOG0(CNOTIFY,"AddConnectNotify SUCCESS\n");
|
|
|
|
if (ContextInfo != NULL)
|
|
{
|
|
ContextInfo[i] = lpNotifyInfo->lpContext;
|
|
}
|
|
|
|
break;
|
|
|
|
case WN_CANCEL:
|
|
MPR_LOG0(CNOTIFY,"AddConnectNotify WN_CANCEL\n");
|
|
//
|
|
// CANCEL shouldn't be returned from NOTIFY_POST calls.
|
|
//
|
|
if (lpNotifyInfo->dwNotifyStatus == NOTIFY_PRE) {
|
|
//
|
|
// If we got the cancel for the first notifyee, then we can
|
|
// stop here.
|
|
//
|
|
if (i == 0) {
|
|
lpNotifyInfo->lpContext = ContextInfo;
|
|
return(status);
|
|
}
|
|
//
|
|
// If we have already successfully called some notifyees, then we
|
|
// must now post notify them of the cancel.
|
|
//
|
|
numNotifyees = i;
|
|
lpNotifyInfo->dwNotifyStatus = NOTIFY_POST;
|
|
i = 0xffffffff;
|
|
}
|
|
break;
|
|
|
|
case WN_RETRY:
|
|
MPR_LOG0(CNOTIFY,"AddConnectNotify WN_RETRY\n");
|
|
//
|
|
// RETRY is only valid if the operation failed and
|
|
// this is a post notification.
|
|
//
|
|
if ((lpNotifyInfo->dwOperationStatus != WN_SUCCESS) &&
|
|
(lpNotifyInfo->dwNotifyStatus == NOTIFY_POST)) {
|
|
|
|
retryFlag = TRUE;
|
|
|
|
if (ContextInfo != NULL)
|
|
{
|
|
ContextInfo[i] = lpNotifyInfo->lpContext;
|
|
}
|
|
|
|
//
|
|
// If we need to retry, then we must now pre-notify those
|
|
// notifyees that we have already post-notified. We don't
|
|
// want to post-notify any more notifyees.
|
|
//
|
|
|
|
if (i > 0) {
|
|
numNotifyees = i;
|
|
lpNotifyInfo->dwNotifyStatus = NOTIFY_PRE;
|
|
i = 0xffffffff;
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
MPR_LOG1(CNOTIFY,"AddConnectNotify returned an error %d\n",status);
|
|
lastError = status;
|
|
break;
|
|
}
|
|
}
|
|
//
|
|
// Restore the pointer to the array of context information.
|
|
//
|
|
lpNotifyInfo->lpContext = ContextInfo;
|
|
|
|
//
|
|
// No matter if other error occured, if one of the notifyees wants
|
|
// a retry, we will return retry.
|
|
//
|
|
if (retryFlag == TRUE) {
|
|
return(WN_RETRY);
|
|
}
|
|
return(lastError);
|
|
}
|
|
|
|
DWORD
|
|
MprCancelConnectNotify(
|
|
LPNOTIFYINFO lpNotifyInfo,
|
|
LPNOTIFYCANCEL lpCancelInfo
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
DWORD i;
|
|
DWORD status;
|
|
DWORD lastError=WN_SUCCESS;
|
|
BOOL retryFlag=FALSE;
|
|
DWORD numNotifyees = GlobalNumNotifyees;
|
|
PVOID *ContextInfo;
|
|
LPNOTIFYEE NotifyEntry=NotifyList;
|
|
|
|
MPR_LOG0(CNOTIFY,"In MprCancelConnectNotify\n");
|
|
|
|
ASSERT_INITIALIZED(NOTIFIEE);
|
|
|
|
//
|
|
// Save away the pointer to the array of context information.
|
|
//
|
|
ContextInfo = (PVOID *) lpNotifyInfo->lpContext;
|
|
|
|
for (i=0; i<numNotifyees; i++,NotifyEntry++)
|
|
{
|
|
if (lpNotifyInfo->dwNotifyStatus == NOTIFY_POST)
|
|
{
|
|
if (ContextInfo && ContextInfo[i] != NULL)
|
|
{
|
|
lpNotifyInfo->lpContext = ContextInfo[i];
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Don't notify if it is a POST notification, and there
|
|
// is no context saved. Here we go directly to the next
|
|
// notifyee (or out of the for loop).
|
|
//
|
|
continue;
|
|
}
|
|
}
|
|
|
|
status = NotifyEntry->PF_CancelConnectNotify(lpNotifyInfo,lpCancelInfo);
|
|
|
|
switch (status) {
|
|
case WN_SUCCESS:
|
|
MPR_LOG0(CNOTIFY,"CancelConnectNotify SUCCESS\n");
|
|
|
|
if (ContextInfo != NULL)
|
|
{
|
|
ContextInfo[i] = lpNotifyInfo->lpContext;
|
|
}
|
|
|
|
break;
|
|
|
|
case WN_CANCEL:
|
|
MPR_LOG0(CNOTIFY,"CancelConnectNotify WN_CANCEL\n");
|
|
//
|
|
// It is assumed that CANCEL won't be returned from
|
|
// NOTIFY_POST calls.
|
|
//
|
|
// If we got the cancel for the first notifyee, then we can
|
|
// stop here.
|
|
//
|
|
if (i == 0) {
|
|
lpNotifyInfo->lpContext = ContextInfo;
|
|
return(status);
|
|
}
|
|
//
|
|
// If we have already successfully called some notifyees, then we
|
|
// must now post notify them of the cancel.
|
|
//
|
|
numNotifyees = i;
|
|
lpNotifyInfo->dwNotifyStatus = NOTIFY_POST;
|
|
i = 0xffffffff;
|
|
break;
|
|
|
|
case WN_RETRY:
|
|
MPR_LOG0(CNOTIFY,"CancelConnectNotify WN_RETRY\n");
|
|
retryFlag = TRUE;
|
|
|
|
if (ContextInfo != NULL)
|
|
{
|
|
ContextInfo[i] = lpNotifyInfo->lpContext;
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
MPR_LOG1(CNOTIFY,"CancelConnectNotify returned an error %d\n",status);
|
|
lastError = status;
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Restore the pointer to the array of context information.
|
|
//
|
|
lpNotifyInfo->lpContext = ContextInfo;
|
|
|
|
//
|
|
// No matter if other error occured, if one of the notifyees wants
|
|
// a retry, we will return retry.
|
|
//
|
|
if (retryFlag == TRUE) {
|
|
return(WN_RETRY);
|
|
}
|
|
return(lastError);
|
|
}
|
|
|