/*++ 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)) { 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) { return(WN_SUCCESS); } NotifyList = (LPNOTIFYEE) LocalAlloc(LPTR,numValues * sizeof(NOTIFYEE)); if (NotifyList == NULL) { return(GetLastError()); } NotifyEntry = NotifyList; // // Load the Notifyees and get their entry points. // for (i=0; i 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; ilpContext; for (i=0; idwNotifyStatus == 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; idwNotifyStatus == 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); }