udfPathMakeValid
str udfPathMakeValid (str)
;-----------------------------------------------------------------------------------------------------------------------------------------
#DefineFunction udfPathMakeValid (strPath, strReplaceChar) ; Version 2.1.
If strPath == "" Then Return ""
strReplaceChar = StrSub (strReplaceChar, 1, 1)
strValid = ""
hdlShlwapi = DllLoad ("SHLWAPI.DLL")
hdlBB = BinaryAlloc (260) ; MAX_PATH = 260

BinaryPokeStr (hdlBB, 0, strPath)
intOffset = Max (0, DllCall (hdlShlwapi, long : "PathSkipRootA", lpbinary : hdlbb) - IntControl (42, hdlbb, 0, 0, 0)) ; CurrentOffset = MemBufferOffset - MemBufferStartAddress.
strFp = BinaryPeekStr (hdlbb, intOffset, BinaryEodGet (hdlBB)) ; StrPos=CurrentOffset, StrLen=until end of string.
strRt = BinaryPeekStr (hdlbb, 0, intOffset) ; StrPos=0=BufferStart, StrLen=CurrentOffset.
blnHasRoot = strRt != ""

If blnHasRoot
   intLen = StrLen (strRt)
   For intI = 1 To intLen
      strChar = StrSub (strRt, intI, 1)
      intResult = DllCall (hdlShlwapi, long : "PathGetCharTypeA", word : Char2Num (strChar))
      Switch @TRUE
      Case intResult == 0 ; GCT_INVALID   0x0000
      Case (intResult & 4) == 4; GCT_WILD      0x0004
         strChar = strReplaceChar
      EndSwitch
      strValid = strValid : strChar
   Next
EndIf

If !blnHasRoot Then blnHasRoot = StrSub (strFp, 1, 1) == "\" ; Handle false positive.
intLen = StrLen (strFp)
For intI = 1 To intLen
   strChar = StrSub (strFp, intI, 1)
   intResult = DllCall (hdlShlwapi, long : "PathGetCharTypeA", word : Char2Num (strChar))
   Switch @TRUE
   Case intResult == 0 ; GCT_INVALID   0x0000
   Case (intResult & 4) == 4 ; GCT_WILD      0x0004
      strChar = strReplaceChar
      Break
   Case strChar == ":"
      If blnHasRoot
         strChar = strReplaceChar
      Else
         blnHasRoot = @TRUE
      EndIf
      Break
   Case strChar == "\"
      If StrSub (strFp, intI - 1, 1) == "\" Then strChar = "" ; No replace, just remove backslash.
   EndSwitch
   strValid = strValid : strChar
Next

; Remove trailing spaces per foldername. Note: Leading spaces are allowed by disksystem.
While StrIndex (strValid, " \", 1, @FWDSCAN)
   strValid = StrReplace (strValid, " \", "\")
EndWhile
; Remove overall leading and trailing spaces.
strValid = StrTrim (strValid)

BinaryEodSet (hdlBB, 0)
BinaryPokeStr (hdlBB, 0, strPath)
intResult = DllCall (hdlShlwapi, long : "PathCanonicalizeA", lpbinary : hdlBB, lpstr : strValid)
If intResult Then strValid = BinaryPeekStr (hdlbb, 0, BinaryEodGet (hdlBB)) ; StrPos=0=BufferStart, StrLen=until end of string.

hdlBB = BinaryFree (hdlBB)
hdlShlwapi = DllFree (hdlShlwapi)
Return strValid
;......................................................................................................................
; Detlev Dalitz.20090705.20090707.
;......................................................................................................................
#EndFunction
;-----------------------------------------------------------------------------------------------------------------------------------------


; Test.
DirChange (DirScript ())
ClipPut ("")

strFilePath1 = "K:\;\F1\F2\File.ext" ; Valid.
strFilePath2 = "D:;\FOL*DER;\<FOLDER>\\\..\;A:?/*.TXT"  ; Invalid.
strFilePath3 = '\/:.,;*?"<>|aA~' : Num2Char (127) : Num2Char (128) : Num2Char (26) : @CRLF ; Invalid.
strFilePath4 = "  aaa \ bbb \ ccc  " ; Invalid.

strReplaceChar = "_"

strResult1 = udfPathMakeValid (strFilePath1, strReplaceChar) ; "K:\;\F1\F2\File.ext"
ClipAppend (strResult1 : @LF)

strResult2 = udfPathMakeValid (strFilePath2, strReplaceChar) ; "D:;\FOLDER;\;A.TXT" ; "D:;\FOL_DER;\;A____.TXT"
ClipAppend (strResult2 : @LF)

strResult3 = udfPathMakeValid (strFilePath3, strReplaceChar) ; "\.,;aA~€" ; "\__.,;______aA~€___"
ClipAppend (strResult3 : @LF)

strResult4 = udfPathMakeValid (strFilePath4, strReplaceChar) ; "aaa\ bbb\ ccc"
ClipAppend (strResult4 : @LF)


;1
;Try to create file.
If DiskExist (strResult1)
   blnResult = DirMake (FilePath (strResult1))
   If blnResult
      If FilePut (strResult1, "123") > 0
         intPID = RunShell ("explorer.exe", '/e,/select,"' : FileFullname (strResult1) : '"', "", @ZOOMED, @GETPROCID)
         Display (10, "Note", "10 seconds to wait" : @LF : "or" : @LF : "Press Enter to continue.")
         blnResult = FileDelete (strResult1)
         strResult1 = FilePath (strResult1)
         strResult1 = ItemRemove (-(ItemExtract (-1, strResult1, "\") == ""), strResult1, "\") ; Remove trailing Backslash.
         While DirExist (strResult1)
            blnResult = DirRemove (strResult1)
            strResult1 = ItemRemove (-1, strResult1, "\")
         EndWhile
         TimeDelay (3)
         blnResult = WinClose (FindWindow ("ExploreWClass"))
      EndIf
   EndIf
EndIf

;2
;Try to create file.
If DiskExist (strResult2)
   blnResult = DirMake (FilePath (strResult2))
   If blnResult
      If FilePut (strResult2, "123") > 0
         intPID = RunShell ("explorer.exe", '/e,/select,"' : FileFullname (strResult2) : '"', "", @ZOOMED, @GETPROCID)
         Display (10, "Note", "10 seconds to wait" : @LF : "or" : @LF : "Press Enter to continue.")
         blnResult = FileDelete (strResult2)
         strResult2 = FilePath (strResult2)
         strResult2 = ItemRemove (-(ItemExtract (-1, strResult2, "\") == ""), strResult2, "\") ; Remove trailing Backslash.
         While DirExist (strResult2)
            blnResult = DirRemove (strResult2)
            strResult2 = ItemRemove (-1, strResult2, "\")
         EndWhile
         TimeDelay (3)
         blnResult = WinClose (FindWindow ("ExploreWClass"))
      EndIf
   EndIf
EndIf


;3
; Try to create folder.
blnResult = DirMake (strResult3)
If blnResult
   intPID = RunShell ("explorer.exe", '/e,"' : strResult3 : '"', "", @ZOOMED, @GETPROCID)
   Display (10, "Note", "10 seconds to wait" : @LF : "or" : @LF : "Press Enter to continue.")
   blnResult = DirRemove (strResult3)
   TimeDelay (2)
   blnResult = WinClose (FindWindow ("ExploreWClass"))
EndIf

;4
;Try to create file.
blnResult = DirMake (FilePath (strResult4))
If blnResult
   If FilePut (strResult4, "123") > 0
      intPID = RunShell ("explorer.exe", '/e,/select,"' : FileFullname (strResult4) : '"', "", @ZOOMED, @GETPROCID)
      Display (10, "Note", "10 seconds to wait" : @LF : "or" : @LF : "Press Enter to continue.")
      blnResult = FileDelete (strResult4)
      strResult4 = FilePath (strResult4)
      strResult4 = ItemRemove (-(ItemExtract (-1, strResult4, "\") == ""), strResult4, "\") ; Remove trailing Backslash.
      While DirExist (strResult4)
         blnResult = DirRemove (strResult4)
         strResult4 = ItemRemove (-1, strResult4, "\")
      EndWhile
      TimeDelay (3)
      blnResult = WinClose (FindWindow ("ExploreWClass"))
   EndIf
EndIf

Exit