// // includes // #include #include #include #define INCL_WINDOWS #define INCL_NETERRORS #define INCL_NETLIB #include "lmui.hxx" #define INCL_BLT_MISC #include "blt.hxx" // AUTO_CURSOR #include "dbgstr.hxx" #include "strnumer.hxx" #include "uiassert.hxx" #include "lmobj.hxx" #include "lmoenum.hxx" // SERVICE_ENUM #include "lmoesvc.hxx" // SERVICE_ENUM #include "regkey.hxx" // REG_KEY #include "lmobjrc.h" // IDS_PROFEXT_* extern "C" { #include #include "profext.h" #include // CONFIGRET #include // CSCONFIGFLAG_DISABLED // we have to do this for a clean compile #undef DBGOUT #include "sysdm.h" // IDH_HWPROFILE #include // REGSTR_PATH_SERVICES #include // NdisMedium* constants } // // global data // HINSTANCE hInst = NULL; // Module handle static int HwProfileHelpIds[] = { IDC_DISABLE, IDH_HWPROFILE+IDC_DISABLE, IDC_ENABLE, IDH_HWPROFILE+IDC_ENABLE, IDC_NONET, IDH_HWPROFILE+IDC_NONET, IDC_ERROR, IDH_HWPROFILE+IDC_ERROR, 0, 0 }; #define SZ_NDIS SZ("NDIS") #define TCH_REGSEPERATOR TCH('\\') #define SZ_REGSEPERATOR SZ("\\") #define SZ_REGPARAMETERS SZ("\\Parameters") #define SZ_REGLINKAGE SZ("\\Linkage") #define SZ_REGMEDIATYPE SZ("MediaType") #define SZ_REGBIND SZ("Bind") APIERR MapCfgMgr32Error( CONFIGRET dwCfgMgr32Error ) { APIERR err = IDS_CFGMGR32_BASE + dwCfgMgr32Error; switch (dwCfgMgr32Error) { case CR_SUCCESS : // CR_NEED_RESTART is considered to be Success case CR_NEED_RESTART : err = NO_ERROR; break; // Just use the CFGMGR out-of-memory error // // case CR_OUT_OF_MEMORY : // err = ERROR_NOT_ENOUGH_MEMORY; // break; // // These are supposedly for Windows 95 only! // case CR_INVALID_ARBITRATOR : case CR_INVALID_NODELIST : case CR_DLVXD_NOT_FOUND : case CR_NOT_SYSTEM_VM : case CR_NO_ARBITRATOR : case CR_DEVLOADER_NOT_READY : ASSERT( FALSE ); // fall through default : break; } return err; } VOID HandleError( HWND hDlg, APIERR err, HWND hwndEdit = NULL ) { NLS_STR nlsError, nlsTitle; if ( nlsError.QueryError() != NERR_Success || nlsTitle.QueryError() != NERR_Success || nlsError.Load( err ) != NERR_Success || nlsTitle.Load( IDS_PROFEXT_ERROR ) != NERR_Success ) { TRACEEOL( "PROFEXT.DLL: HandleError failure" ); ASSERT( FALSE ); return; } if (hwndEdit != NULL) { ::SetWindowText( hwndEdit, nlsError.QueryPch() ); ::ShowWindow( hwndEdit, SW_SHOW ); } if (err != IDS_PROFEXT_NOADAPTERS) { REQUIRE( IDOK == ::MessageBox( hDlg, nlsError.QueryPch(), nlsTitle.QueryPch(), MB_ICONSTOP | MB_OK ) ); } } APIERR IsDisabled( ULONG ulProfileID, DEVINSTID devinst, BOOL* pfIsDisabled ) { TRACEEOL( "IsDisabled( " << ulProfileID << ", \"" << devinst << "\") " ); ASSERT( pfIsDisabled != NULL ); APIERR err = NERR_Success; ULONG ulValue = 0; CONFIGRET configret = ::CM_Get_HW_Prof_Flags( devinst, ulProfileID, &ulValue, 0x0 ); err = MapCfgMgr32Error( configret ); if (err != NERR_Success) { TRACEEOL( "\terror " << configret ); return err; } *pfIsDisabled = !!(ulValue & CSCONFIGFLAG_DISABLED); TRACEEOL( (CHAR*)((*pfIsDisabled)?"\tis disabled":"\tis enabled") ); return err; } APIERR Disable( ULONG ulProfileID, DEVINSTID devinst, BOOL fDisable ) { APIERR err = NERR_Success; ULONG ulValue = 0; CONFIGRET configret = ::CM_Get_HW_Prof_Flags( devinst, ulProfileID, &ulValue, 0x0 ); err = MapCfgMgr32Error( configret ); if (err != NERR_Success) { TRACEEOL( "\tEnable: CM_Get_HW_Prof_Flags error " << configret ); return err; } if (fDisable) { if ( ulValue & CSCONFIGFLAG_DISABLED ) { TRACEEOL( "Disable: \"" << devinst << "\" already disabled" ); return err; } ulValue |= CSCONFIGFLAG_DISABLED; } else { if ( !(ulValue & CSCONFIGFLAG_DISABLED) ) { TRACEEOL( "Disable: \"" << devinst << "\" already enabled" ); return err; } ulValue &= ~CSCONFIGFLAG_DISABLED; } configret = ::CM_Set_HW_Prof_Flags( devinst, ulProfileID, ulValue, 0x0 ); err = MapCfgMgr32Error( configret ); if (err != NERR_Success) { TRACEEOL( "\tDisable: CM_Set_HW_Prof_Flags error " << configret ); } else { TRACEEOL( "\tDisable: \"" << devinst << (CHAR*)((fDisable)?"\" now disabled":"\" now enabled") ); } return err; } APIERR BoundServiceIsWanMediaType( NLS_STR& nlsBoundService, BOOL* pfWANMediaType, REG_KEY& regkeyHKLM ) { const TCHAR * pchBoundService = nlsBoundService.QueryPch(); ISTR istrBoundService( nlsBoundService ); if ( nlsBoundService.strrchr( &istrBoundService, TCH_REGSEPERATOR ) ) { ++istrBoundService; pchBoundService = nlsBoundService.QueryPch( istrBoundService ); } // open HKLM\CurrentControlSet\Services\\Parameters key NLS_STR nlsRegPath( REGSTR_PATH_SERVICES ); nlsRegPath += SZ_REGSEPERATOR; nlsRegPath += pchBoundService; nlsRegPath += SZ_REGPARAMETERS; APIERR err = nlsRegPath.QueryError(); if ( err != NERR_Success ) { DBGEOL( "BoundServiceIsWanMediaType: string error " << err ); return err; } TRACEEOL( "BoundServiceIsWanMediaType: key \"" << nlsRegPath << "\"" ); REG_KEY regkeyParameters(regkeyHKLM, nlsRegPath, KEY_READ); if ( (err = regkeyParameters.QueryError()) != NERR_Success ) { TRACEEOL( "BoundServiceIsWanMediaType: key \"" << nlsRegPath << "\" error " << err ); return err; } DWORD dwMediaType = 0; if ( (err = regkeyParameters.QueryValue( SZ_REGMEDIATYPE, &dwMediaType)) != NERR_Success ) { TRACEEOL( "BoundServiceIsWanMediaType: mediatype error " << err ); return err; } TRACEEOL( "BoundServiceIsWanMediaType: media type " << dwMediaType ); switch (dwMediaType-1) { case NdisMedium802_3: case NdisMedium802_5: case NdisMediumFddi: case NdisMediumLocalTalk: case NdisMediumDix: case NdisMediumArcnetRaw: case NdisMediumArcnet878_2: case NdisMediumAtm: *pfWANMediaType = FALSE; break; case NdisMediumWan: case NdisMediumWirelessWan: case NdisMediumIrda: *pfWANMediaType = TRUE; break; default: DBGEOL( "BoundServiceIsWanMediaType: invalid media type " << dwMediaType ); *pfWANMediaType = TRUE; break; } return NERR_Success; } APIERR IsWanMediaType( const TCHAR * pszServiceName, BOOL* pfWANMediaType) { TRACEEOL( "IsWanMediaType: checking \"" << pszServiceName << "\"" ); // open HKLM key REG_KEY regkeyHKLM(HKEY_LOCAL_MACHINE, NULL, KEY_READ); APIERR err = regkeyHKLM.QueryError(); if ( err != NERR_Success ) { DBGEOL( "IsWanMediaType: HKLM error " << err ); return err; } // open HKLM\CurrentControlSet\Services\\Linkage key NLS_STR nlsRegPath( REGSTR_PATH_SERVICES ); nlsRegPath += SZ_REGSEPERATOR; nlsRegPath += pszServiceName; nlsRegPath += SZ_REGLINKAGE; if ( (err = nlsRegPath.QueryError()) != NERR_Success ) { DBGEOL( "IsWanMediaType: string error " << err ); return err; } TRACEEOL( "IsWanMediaType: key \"" << nlsRegPath << "\"" ); REG_KEY regkeyLinkage(regkeyHKLM, nlsRegPath, KEY_READ); if ( (err = regkeyLinkage.QueryError()) != NERR_Success ) { TRACEEOL( "IsWanMediaType: key \"" << nlsRegPath << "\" error " << err ); return err; } // get Bind parameter and extract service name(s) STRLIST* pstrlistBind = NULL; if ( (err = regkeyLinkage.QueryValue( SZ_REGBIND, &pstrlistBind )) != NERR_Success || (err = ((pstrlistBind != NULL) ? NERR_Success : ERROR_NOT_ENOUGH_MEMORY)) != NERR_Success ) { TRACEEOL( "IsWanMediaType: bind value error " << err ); return err; } ITER_STRLIST iterslBind( *pstrlistBind ); NLS_STR* pnlsBind = NULL; *pfWANMediaType = FALSE; while ( (pnlsBind = iterslBind.Next()) != NULL ) { err = BoundServiceIsWanMediaType( *pnlsBind, pfWANMediaType, regkeyHKLM ); if (err != NERR_Success || *pfWANMediaType ) break; } delete pstrlistBind; // CODEWORK I have seen problems with this line return err; } /* * if fSet is FALSE, set *pfNoNetworkProfile to TRUE if no network * device is enabled, set to FALSE otherwise * * if fSet is TRUE and *pfNoNetworkProfile is FALSE, * enable all network devices * * if fSet is TRUE and *pfNoNetworkProfile is TRUE, * disable all network devices */ APIERR DoNetworkProfile( ULONG ulProfileID, BOOL fSet, BOOL* pfNoNetworkProfile ) { AUTO_CURSOR autocur; ASSERT( pfNoNetworkProfile != NULL ); APIERR err = NERR_Success; if (!fSet) *pfNoNetworkProfile=TRUE; do // false loop { TRACEEOL( "DoNetworkProfile: enumerating NDIS services"); SERVICE_ENUM svcenum( NULL, TRUE, SERVICE_KERNEL_DRIVER, SZ_NDIS ); if ( (err = svcenum.QueryError()) != NERR_Success || (err = svcenum.GetInfo()) != NERR_Success ) { TRACEEOL( "DoNetworkProfile: error " << err << " opening svcenum" ); break; } BOOL fFoundAdapter = FALSE; SERVICE_ENUM_ITER svciter( svcenum ); const SERVICE_ENUM_OBJ* psvc; while( ( psvc = svciter() ) != NULL ) { const TCHAR* pszServiceName = psvc->QueryServiceName(); if ( 0 == ::stricmpf( pszServiceName, SZ_NDIS ) ) continue; BOOL fWANMediaType = FALSE; if ( (err = IsWanMediaType(pszServiceName, &fWANMediaType)) != NERR_Success) { // // All errors are ignored, and we assume WAN MediaType // TRACEEOL( "DoNetworkProfile: ignoring error " << err << " checking mediatype of \"" << pszServiceName << "\"" ); err = NERR_Success; continue; } else if (fWANMediaType) { TRACEEOL( "DoNetworkProfile: skipping service \"" << pszServiceName << "\" due to mediatype" ); continue; } ULONG cch = 0; CONFIGRET configret = ::CM_Get_Device_ID_List_Size( &cch, pszServiceName, CM_GETIDLIST_FILTER_SERVICE ); if ( (err = MapCfgMgr32Error( configret )) != NERR_Success ) { TRACEEOL("DoNetworkProfile: Get_Device_ID_List_Size returned " << configret ); if (configret == CR_NO_SUCH_VALUE) { ASSERT( FALSE ); continue; } break; } BUFFER bufDeviceIDs( cch*sizeof(TCHAR) ); if ( (err = bufDeviceIDs.QueryError()) != NERR_Success ) break; do { configret = ::CM_Get_Device_ID_List( pszServiceName, (TCHAR *)(bufDeviceIDs.QueryPtr()), bufDeviceIDs.QuerySize() / sizeof(TCHAR), CM_GETIDLIST_FILTER_SERVICE ); if (configret == CR_BUFFER_SMALL) { cch *= 2; if ( (err = bufDeviceIDs.Resize(cch*sizeof(TCHAR))) != NERR_Success ) break; } else if (configret == CR_NO_SUCH_VALUE) { ASSERT( FALSE ); continue; } } while (configret == CR_BUFFER_SMALL); const TCHAR * pchDeviceID = (const TCHAR *)bufDeviceIDs.QueryPtr(); while ( *pchDeviceID != TCH('\0') ) { fFoundAdapter = TRUE; DEVINSTID devinst = (DEVINSTID)pchDeviceID; if (fSet) { if ( (err = Disable( ulProfileID, devinst, *pfNoNetworkProfile)) != NERR_Success) break; } else { BOOL fIsDisabled = FALSE; if ( (err = IsDisabled( ulProfileID, devinst, &fIsDisabled)) != NERR_Success) break; if (!fIsDisabled) { *pfNoNetworkProfile = FALSE; break; } } pchDeviceID += ::strlenf(pchDeviceID) + 1; } } TRACEEOL( "DoNetworkProfile: enumerated NDIS services"); if ( !fFoundAdapter && err == NERR_Success ) { TRACEEOL( "DoNetworkProfile: no adapters found" ); err = IDS_PROFEXT_NOADAPTERS; } } while (FALSE); // false loop return err; } BOOL DllMain( PVOID hModule, ULONG Reason, PCONTEXT pContext ) /*++ Routine Description: This is the standard DLL entrypoint routine, called whenever a process or thread attaches or detaches. Arguments: hModule - PVOID parameter that specifies the handle of the DLL Reason - ULONG parameter that specifies the reason this entrypoint was called (either PROCESS_ATTACH, PROCESS_DETACH, THREAD_ATTACH, or THREAD_DETACH). pContext - ??? Return value: Returns true if initialization compeleted successfully, false is not. --*/ { hInst = (HINSTANCE)hModule; DBG_UNREFERENCED_PARAMETER(pContext); switch(Reason) { case DLL_PROCESS_ATTACH: DisableThreadLibraryCalls(hInst); case DLL_PROCESS_DETACH: case DLL_THREAD_ATTACH: case DLL_THREAD_DETACH: break; } return TRUE; } // DllMain BOOL CALLBACK ExtensionPropSheetPageProc( LPVOID lpv, LPFNADDPROPSHEETPAGE lpfnAddPropSheetPageProc, LPARAM lParam ) /*++ Routine Description: Arguments: lpv Pointer to an application-defined value that describes an item for which a property sheet page is to be created. This parameter can be NULL. lpfnAddPropSheetPageProc Pointer to the AddPropSheetPageProc function. The extension dynamic-link library (DLL) calls this function to add a page to the property sheet. lParam Application-defined 32-bit value. Return Value: If the function succeeds, the return value is TRUE. If the function fails, the return value is FALSE. --*/ { PROPSHEETPAGE PropPage; HPROPSHEETPAGE hPropPage; PropPage.dwSize = sizeof(PROPSHEETPAGE); PropPage.dwFlags = PSP_DEFAULT; PropPage.hInstance = hInst; PropPage.pszTemplate = MAKEINTRESOURCE(DLG_HWP_EXT); PropPage.pszIcon = NULL; PropPage.pszTitle = NULL; PropPage.pfnDlgProc = NetworkPropDlg; PropPage.lParam = lParam; PropPage.pfnCallback = NULL; hPropPage = CreatePropertySheetPage(&PropPage); if (hPropPage == NULL) { return FALSE; } (lpfnAddPropSheetPageProc)(hPropPage, 0); return TRUE; } // ExtensionPropSheetPageProc typedef struct { LONG ulProfile; BOOL fNoNet; BOOL fError; } PROFEXT_INTERNAL; BOOL APIENTRY NetworkPropDlg( HWND hDlg, UINT uMessage, WPARAM wParam, LPARAM lParam ) { ULONG ulProfile = 0; APIERR err = NERR_Success; switch (uMessage) { case WM_INITDIALOG: { PROFEXT_INTERNAL* pprofext = new PROFEXT_INTERNAL; // CODEWORK I should free this at some point ASSERT( pprofext != NULL ); ::memsetf( pprofext, '\0', sizeof(PROFEXT_INTERNAL) ); ::SetWindowLong(hDlg, DWL_USER, (LONG)pprofext); // // on WM_INITDIALOG call, property sheet's lParam field // contains the profile ID, save it in window long word for // use with other messages later // ulProfile = (ULONG)((LPPROPSHEETPAGE)lParam)->lParam; ASSERT( (LONG)ulProfile >= 0 ); pprofext->ulProfile = ulProfile; BOOL fNoNetworkProfile = FALSE; err = DoNetworkProfile( ulProfile, FALSE, &fNoNetworkProfile ); if (err != NERR_Success) { HWND hwndEdit = ::GetDlgItem(hDlg, IDC_ERROR); ASSERT( hwndEdit != NULL ); HandleError( hDlg, err, hwndEdit ); pprofext->fError = TRUE; } else { pprofext->fNoNet = (fNoNetworkProfile)?1:0; } // // Call CM_Get_Hardware_Profile_Info to get info about // the specified profile (ulProfile). // return FALSE; } case WM_NOTIFY: if (!lParam) { break; } switch (((NMHDR *)lParam)->code) { case PSN_SETACTIVE: { PROFEXT_INTERNAL* pprofext = (PROFEXT_INTERNAL*)::GetWindowLong(hDlg, DWL_USER); ASSERT( pprofext != NULL ); HWND hwndCheckbox = ::GetDlgItem(hDlg, IDC_NONET); HWND hwndEnableText = ::GetDlgItem(hDlg, IDC_ENABLE); HWND hwndDisableText = ::GetDlgItem(hDlg, IDC_DISABLE); ASSERT( hwndCheckbox && hwndEnableText && hwndDisableText ); ::EnableWindow( hwndEnableText, pprofext->fNoNet && !(pprofext->fError) ); ::EnableWindow( hwndDisableText, !(pprofext->fNoNet) && !(pprofext->fError) ); if (pprofext->fError) { ::EnableWindow( hwndCheckbox, FALSE ); } else { ::SendMessage( hwndCheckbox, BM_SETCHECK, (pprofext->fNoNet)?1:0, 0 ); } } break; case PSN_KILLACTIVE: { PROFEXT_INTERNAL* pprofext = (PROFEXT_INTERNAL*)::GetWindowLong(hDlg, DWL_USER); ASSERT( pprofext != NULL ); // // validate selections, this page is active until I return FALSE // in DWL_MSGRESULT // if (pprofext->fError) break; // error or no adapter as initial state TRACEEOL( "NetworkPropDlg: pprofext->fNoNet is " << pprofext->fNoNet ); HWND hwnd = ::GetDlgItem(hDlg, IDC_NONET); ASSERT( hwnd != NULL ); BOOL fCurrentNoNet = (::SendMessage(hwnd, BM_GETCHECK, 0, 0) != 0) ? TRUE : FALSE; TRACEEOL( "NetworkPropDlg: fCurrentNoNet is " << fCurrentNoNet ); if (pprofext->fNoNet != fCurrentNoNet) { err = DoNetworkProfile( pprofext->ulProfile, TRUE, &fCurrentNoNet ); if (err != NERR_Success) { HandleError( hDlg, err ); ::SetWindowLong(hDlg, DWL_MSGRESULT, TRUE); // TRUE if error break; } } pprofext->fNoNet = fCurrentNoNet; ::SetWindowLong(hDlg, DWL_MSGRESULT, FALSE); // TRUE if error } break; case PSN_RESET: // // user canceled the property sheet // break; } break; case WM_HELP: WinHelp((HWND)((LPHELPINFO)lParam)->hItemHandle, HELP_FILE, HELP_WM_HELP, (DWORD)(LPTSTR)HwProfileHelpIds); break; case WM_CONTEXTMENU: WinHelp((HWND)wParam, HELP_FILE, HELP_CONTEXTMENU, (DWORD)(LPTSTR)HwProfileHelpIds); break; case WM_COMMAND: default: return FALSE; break; } return TRUE; } // NetworkPropDlg