*- 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