>*- Smb2CacheFix.prg >*- >*- This process MUST be run on all workstations that participate >*- in shared data access. >*- >*- The VFP Registry class must already be available >*- via a SET CLASSLIB or SET PROCEDURE command. >*- >#DEFINE HKEY_LOCAL_MACHINE -2147483646 && BITSET(0,31)+2 >#DEFINE SMB2_REGISTRY_PATH "SYSTEM\CurrentControlSet\Services\LanmanWorkstation\Parameters" >#DEFINE REG_DWORD 4 && A 32-bit number. >#DEFINE ERROR_SUCCESS 0 && OK > >PRIVATE pcDetail >LOCAL lcDefPath AS String; > , lcOldErr AS String; > , loRegistry AS "MyRegistry" > >*- Detect Windows Vista OR Higher >IF VAL(OS(3))=>6 > > *- Detect SMB2 buffering > loRegistry = NEWOBJECT("MyRegistry") && See class definition below > IF Smb2CachesData(loRegistry) > > *- See if the user wants to change buffer settings > IF MESSAGEBOX("Do you want to zero out the SMB2 cache settings?"; > ,32+4,"Problem with SMB2 Cache Settings")=6 > *- Try to change the buffer settings > lcOldErr = ON("Error") > ON ERROR * > loRegistry.DWORD_SetRegValue( HKEY_LOCAL_MACHINE; > , SMB2_REGISTRY_PATH; > , "FileInfoCacheLifetime"; > , 0) > loRegistry.DWORD_SetRegValue( HKEY_LOCAL_MACHINE; > , SMB2_REGISTRY_PATH; > , "FileNotFoundCacheLifetime"; > , 0) > loRegistry.DWORD_SetRegValue( HKEY_LOCAL_MACHINE; > , SMB2_REGISTRY_PATH; > , "DirectoryCacheLifetime"; > , 0) > ON ERROR &lcOldErr > > *- Retest cache ettings and display the appropriate message > IF Smb2CachesData(loRegistry) > *- Failure > MESSAGEBOX("Failed to change the settings."; > +CHR(13)+CHR(13); > +"Try to re-run this process with Administrator privileges."; > ,16,"Status") > ELSE > *- Success > MESSAGEBOX("Succeeded in changing the SMB2 cache settings."; > +CHR(13)+CHR(13); > +"You must reboot your computer for the changes to take affect."; > ,64,"Status") > ENDIF > RETURN .F. && Exit application > ENDIF > ENDIF >ENDIF > > >******************************************* >DEFINE CLASS MyRegistry AS Registry > PROCEDURE DWORD_GetRegValue > LPARAMETERS tnRegRoot, tcSubKey, tcOption > LOCAL lnKeyHandle, lpdwType, lpcbData, lpbData, lnValue > m.lnKeyHandle = 0 > m.lpdwType = REG_DWORD > m.lpcbData = 4 > m.lpbData = REPLICATE(CHR(0),4) > m.lnValue = 0 > > * Load the API functions > nErrCode = THIS.LoadRegFuncs() > IF m.nErrCode # ERROR_SUCCESS > RETURN .NULL. > ENDIF > > IF RegOpenKey(tnRegRoot, tcSubKey, @lnKeyHandle) = ERROR_SUCCESS > RegQueryValueEx(m.lnKeyHandle, tcOption, 0, @lpdwType, @lpbData, @lpcbData) > RtlMoveMemory(@lnValue, lpbData, 4) > RegCloseKey(m.lnKeyHandle) > RETURN m.lnValue > ELSE > RETURN .NULL. > ENDIF > ENDPROC > > PROCEDURE DWORD_SetRegValue > LPARAMETERS tnRegRoot, tcSubKey, tcOption, tnValue > LOCAL lnKeyHandle,lpdwType,lpcbData,lpbData > m.lnKeyHandle = 0 > m.lpdwType = REG_DWORD > m.lpcbData = 4 > * Load the API functions > nErrCode = THIS.LoadRegFuncs() > IF m.nErrCode # ERROR_SUCCESS > RETURN .NULL. > ENDIF > > m.lpbData = BinToChar(tnValue, 4) > > IF RegOpenKey(tnRegRoot, tcSubKey, @lnKeyHandle) = ERROR_SUCCESS > RegSetValueEx(m.lnKeyHandle,tcOption, 0, @lpdwType, @lpbData, @lpcbData) > RegCloseKey(m.lnKeyHandle) > ENDIF > ENDPROC >ENDDEFINE > > >FUNCTION Smb2CachesData( toRegistry ) > LOCAL laSettings[1]; > , llRtnVal AS Boolean; > , lnGoodSettings AS Number; > , lnX AS Number > > *- Get an array of registry settings > DIMENSION laSettings[1] > IF toRegistry.EnumOptions(@laSettings; > , SMB2_REGISTRY_PATH; > , HKEY_LOCAL_MACHINE; > , .F.) = ERROR_SUCCESS > *- Test the cache settings. > *- All three must be zero to pass > lnGoodSettings = 0 > FOR lnX = 1 TO ALEN(laSettings, 1) > IF VARTYPE(laSettings[lnX, 1])="C" ; > AND INLIST(UPPER(laSettings[lnX, 1]); > , "DIRECTORYCACHELIFETIME"; > , "FILEINFOCACHELIFETIME"; > , "FILENOTFOUNDCACHELIFETIME"); > AND CharToBin(laSettings[lnX, 2])=0 > lnGoodSettings = lnGoodSettings + 1 > ENDIF > NEXT lnX > llRtnVal = lnGoodSettings<3 > ENDIF > RETURN llRtnVal >ENDFUNC > > >FUNCTION BinToChar( tnNum, tnByteSize ) > *- Converts a DWORD value in binary string form back into > *- a numeric value > LOCAL lnX, lcNum > > tnByteSize = IIF(VARTYPE(tnByteSize)="N", tnByteSize, 4) > lcNum = '' > FOR lnX=1 to tnByteSize > lcNum = lcNum + CHR(INT(tnNum/(256^(lnX-1)))%256) > NEXT > RETURN lcNum >ENDFUNC > > >FUNCTION CharToBin( tcWord ) > *- Converts a DWORD value in binary string form back into > *- a numeric value > LOCAL lnX, lnWord > > lnWord = 0 > FOR lnX = 1 TO LEN(tcWord) > lnWord = lnWord + (ASC(SUBSTR(tcWord, lnX, 1)) * (2 ^ (8 * (lnX - 1)))) > ENDFOR > RETURN lnWord >ENDFUNC